Improper authorization control for web services - RDS - Go

Improper authorization control for web services - RDS - Go

Need

Enhancement of authorization controls for web services - RDS

Context

  • Usage of Go 1.13 for building high-performance and scalable applications
  • Usage of gin-gonic/gin for building web applications and APIs in Go
  • Usage of gorm for Object-Relational Mapping (ORM) in Go
  • Usage of GORM MySQL dialect for database operations

Description

Non compliant code

        package main

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
	gorm.Model
	Name string
}

var DB *gorm.DB

func main() {
	var err error
	DB, err = gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic("failed to connect database")
	}
	DB.AutoMigrate(&User{})

	r := gin.Default()
	r.GET("/users", GetUsers)
	r.Run()
}

func GetUsers(c *gin.Context) {
	var users []User
	if err := DB.Find(&users).Error; err != nil {
		c.JSON(500, gin.H{"error": "Error retrieving users"})
		return
	}
	c.JSON(200, users)
}
        
        

In the above code, we have a simple Go web application using the Gin framework and Gorm for database operations. The application connects to a MySQL database (which could be an RDS instance) and exposes an endpoint /users to fetch all users from the database.

The major security vulnerability here is the lack of proper authorization control. Anybody who can access this web service can get all the users' information because the /users endpoint is public and doesn't require any form of authentication or authorization.

Another issue is the hard-coded database credentials in the code. If an attacker gets access to the source code, they can easily connect to the database and compromise its data.

Also, the database is configured to be publicly accessible, which is a significant security risk. It's generally a best practice to restrict direct access to the database and only allow access from specific, trusted sources.

Steps

  • Implement proper authentication and authorization mechanisms for accessing the RDS instance.
  • Ensure that the RDS instance is not publicly accessible and is only accessible to authorized users or services.
  • Use secure connection protocols (e.g., SSL/TLS) to encrypt the communication between the backend application and the RDS instance.
  • Implement strong access control policies to restrict access to sensitive data stored in the RDS instance.
  • Regularly monitor and audit the access logs of the RDS instance to detect any unauthorized access attempts.
  • Keep the RDS instance and the backend application up to date with the latest security patches and updates.
  • Regularly perform security assessments and penetration testing to identify and fix any vulnerabilities in the application and the RDS instance.

Compliant code

        package main

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
	gorm.Model
	Name string
}

var DB *gorm.DB

func main() {
	var err error
	DB, err = gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic("failed to connect database")
	}
	DB.AutoMigrate(&User{})

	r := gin.Default()
	r.Use(AuthMiddleware())
	r.GET("/users", GetUsers)
	r.Run()
}

func GetUsers(c *gin.Context) {
	var users []User
	if err := DB.Find(&users).Error; err != nil {
		c.JSON(500, gin.H{"error": "Error retrieving users"})
		return
	}
	c.JSON(200, users)
}

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Implement your authorization logic here
		// For example, you can check the request headers for a valid JWT
		// If the token is valid, you can continue with the request
		// If the token is invalid, you can return an error
	}
}
        
        

The original code was vulnerable due to the lack of proper authorization control for accessing the RDS instance. Any user could access the "/users" endpoint and retrieve all users from the database. This could lead to unauthorized access and potential data leakage.

The fixed code introduces an authentication middleware to the Gin router. This middleware function, AuthMiddleware(), is called before the GetUsers handler function. The purpose of this middleware is to implement the necessary authorization logic to ensure that only authenticated and authorized users can access the "/users" endpoint.

In the AuthMiddleware() function, you should implement your authorization logic. For example, you can check the request headers for a valid JWT (JSON Web Token). If the token is valid, you can continue with the request. If the token is invalid, you can return an error and prevent the user from accessing the endpoint.

This way, we ensure that the RDS instance is not publicly accessible and is only accessible to authorized users or services. This significantly reduces the risk of unauthorized access and data leakage.

References