Skip to main content

Improper authorization control for web services

Need

Enhancement of authorization control for web services

Context

  • Usage of Go 1.16 for developing high-performance and scalable applications
  • Usage of gin-gonic/gin for building web applications and APIs in Go

Description

Non compliant code

package main

import (
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()

r.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
// Fetch user based on id
// Return user data
})

r.Run() // listen and serve on 0.0.0.0:8080
}

In this code, we have a simple web server using the Gin framework in Go. The server has a single route /user/:id which fetches and returns user data based on the id parameter.

This code is vulnerable because it does not have any authorization control in place. Any client can send a GET request to /user/:id and retrieve the data of any user just by knowing their id.

There's no mechanism to check if the client is authenticated and authorized to access the data they're requesting. This means that sensitive user data can be accessed by malicious actors, leading to a breach of privacy and potential misuse of data.

To fix this vulnerability, we need to add an authentication and authorization layer to our application. This could be in the form of a middleware that checks if a valid token is present in the request header and if the token belongs to the user whose data is being requested.

Steps

  • Implement an authentication mechanism to verify the identity of the user making the request.
  • Implement an authorization mechanism to determine if the authenticated user has the necessary permissions to access the requested resource.
  • Use a secure session management mechanism to maintain the user's authentication state.
  • Ensure that sensitive data is not exposed in the response unless the user is authorized to access it.
  • Regularly review and update the authentication and authorization mechanisms to address any potential vulnerabilities.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
)

func main() {
r := gin.Default()

store := cookie.NewStore([]byte("secret"))
r.Use(sessions.Sessions("mysession", store))

r.GET("/login", func(c *gin.Context) {
// Implement your login logic here
// If login is successful, set the user id in the session
session := sessions.Default(c)
session.Set("user_id", "authenticated user id")
session.Save()
})

r.GET("/user/:id", func(c *gin.Context) {
session := sessions.Default(c)
user := session.Get("user_id")
if user == nil {
c.JSON(401, gin.H{"error": "unauthorized"})
return
}

id := c.Param("id")
// Check if the user has the necessary permissions to access the requested resource
// Fetch user based on id
// Return user data
})

r.Run() // listen and serve on 0.0.0.0:8080
}

The updated code now includes an authentication and authorization mechanism.

Firstly, we have added a new route /login where the login logic should be implemented. If the login is successful, the user id is stored in the session. We are using the github.com/gin-contrib/sessions package for session management. The session data is stored in a cookie and is encrypted using a secret key.

In the /user/:id route, we first check if the user is authenticated by checking if the user id exists in the session. If the user is not authenticated, we return a 401 unauthorized error. If the user is authenticated, we then check if the user has the necessary permissions to access the requested resource. If the user has the necessary permissions, we fetch and return the user data.

This way, we ensure that only authenticated and authorized users can access the user data.

References