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

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

Need

Implementation of secure and properly configured HTTP headers

Context

  • Usage of Python 3 for general-purpose programming and scripting
  • Usage of Django for building web applications in Python

Description

Non compliant code

        from django.http import HttpResponse

def some_view(request):
    response = HttpResponse()
    response['X-Frame-Options'] = 'SAMEORIGIN'
    return response
        
        

In the above code, the Django application is using the X-Frame-Options HTTP header to prevent the page from being embedded in an iframe. This is a protection mechanism against clickjacking attacks, where an attacker tricks a user into clicking on something different to what the user perceives they are clicking on.

The X-Frame-Options header is set to SAMEORIGIN, which means the page can only be displayed in a frame on the same origin as the page itself.

However, this method of protection is considered deprecated, as it can be bypassed using several iframe layers. This means an attacker could still potentially carry out a clickjacking attack.

The vulnerability lies in the reliance on the X-Frame-Options header as the only protection mechanism against clickjacking. More modern and secure alternatives, such as Content Security Policy (CSP) with the frame-ancestors directive, should be used instead.

Steps

  • Replace the deprecated X-Frame-Options header with the Content-Security-Policy (CSP) header.
  • In the CSP header, use the 'frame-ancestors' directive to control which websites can embed your page.
  • Set the 'frame-ancestors' directive to 'self' to allow only your own site to embed your page, similar to 'SAMEORIGIN' in X-Frame-Options.
  • Ensure that all server responses include the CSP header with the 'frame-ancestors' directive.
  • Test the implementation to ensure that it works as expected and does not break any functionality.

Compliant code

        from django.http import HttpResponse

def some_view(request):
    response = HttpResponse()
    response['Content-Security-Policy'] = "frame-ancestors 'self'"
    return response
        
        

The above code fixes the vulnerability by replacing the deprecated X-Frame-Options header with the Content-Security-Policy (CSP) header.

The Content-Security-Policy is a security header that allows you to control resources the user agent is allowed to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints. This helps guard against cross-site scripting attacks ( XSS).

In this case, we are using the frame-ancestors directive in the CSP header. The frame-ancestors directive specifies valid parents that may embed a page using frame, iframe, object, embed, or applet.

Setting frame-ancestors to 'self' means that only the same site can embed this page, which is similar to the 'SAMEORIGIN' setting in X-Frame-Options. This effectively prevents other sites from embedding your page, protecting against clickjacking.

After implementing this change, it's important to test the application to ensure that the new header does not break any functionality.

References