Insecure or unset HTTP headers - X-Frame Options - Go

Insecure or unset HTTP headers - X-Frame Options - Go

Need

Implementation of secure and properly configured HTTP headers

Context

  • Usage of Go 1.16 for building scalable and efficient applications
  • Usage of gin-gonic/gin for building web applications in Go

Description

Non compliant code

        package main

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

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

	r.GET("/", func(c *gin.Context) {
		c.Header("X-Frame-Options", "SAMEORIGIN")
		c.JSON(200, gin.H{
			"message": "hello world",
		})
	})

	r.Run()
}
        
        

The above Go code is a simple web server built using the Gin framework. The server is set to respond to GET requests at the root ("/") URL.

In the GET request handler, the X-Frame-Options HTTP header is set to "SAMEORIGIN". This instructs the browser to only allow the page to be framed by pages from the same origin (i.e., the same domain, protocol, and port).

The X-Frame-Options header is a security measure designed to protect against clickjacking attacks. However, it is considered deprecated because its protection can be bypassed using several iframe layers.

In this code, the X-Frame-Options header is the only protection mechanism against clickjacking. This is a vulnerability because more modern and secure mechanisms, such as Content Security Policy (CSP), are not being used. Furthermore, the X-Frame-Options header is not set for all server responses, only for those to the root URL, leaving other pages potentially unprotected.

Steps

  • Replace the use of X-Frame-Options header with Content-Security-Policy header.
  • Set the Content-Security-Policy header value to 'frame-ancestors 'self'' to allow the page to be framed only by itself.
  • Ensure that the Content-Security-Policy header is set on all server responses.
  • Test the application to verify that it is no longer vulnerable to clickjacking attacks.

Compliant code

        package main

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

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

	r.GET("/", func(c *gin.Context) {
		c.Header("Content-Security-Policy", "frame-ancestors 'self'")
		c.JSON(200, gin.H{
			"message": "hello world",
		})
	})

	r.Run()
}
        
        

The original code was vulnerable to clickjacking attacks because it used the X-Frame-Options header as the only protection mechanism. This header is considered deprecated and its protection can be bypassed using several iframe layers.

The fixed code replaces the use of the X-Frame-Options header with the Content-Security-Policy header. The Content-Security-Policy header is set to 'frame-ancestors 'self'', which means that the page can only be framed by itself. This effectively prevents clickjacking attacks because an attacker cannot frame the page within their own website.

The Content-Security-Policy header is set on all server responses, ensuring that the protection is applied consistently across the application.

After applying this fix, it is recommended to test the application to verify that it is no longer vulnerable to clickjacking attacks.

References