Insecure or unset HTTP headers - Strict Transport Security - Python

Insecure or unset HTTP headers - Strict Transport Security - Python

Need

Implementation of Strict-Transport-Security (HSTS) header with an appropriate max-age value

Context

  • Usage of Python 3 for writing and executing Python code
  • Usage of Django for building web applications in Python

Description

Non compliant code

        from django.http import HttpResponse
def insecure_header(request):
    response = HttpResponse()
    return response
        
        

In this code snippet, we have a Django view function insecure_header that returns an HttpResponse without setting the Strict-Transport-Security header.

The HTTP Strict Transport Security (HSTS) header is a security feature that helps protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure HTTPS connections, and never via the insecure HTTP protocol.

By not setting the Strict-Transport-Security header or setting it with a short max-age, the application is vulnerable to attacks such as SSL stripping, where an attacker can downgrade the connection from HTTPS to HTTP.

In the case of a short max-age, the browser will only enforce HSTS for the duration specified in max-age. If it's too short, it may not be effective in preventing attacks.

The missing or insecurely set Strict-Transport-Security header can expose the application to various man-in-the-middle (MITM) attacks and can lead to the exposure of sensitive information.

Steps

  • Identify the response object where the HTTP headers need to be set.
  • Add the Strict-Transport-Security (STS) header to the response object.
  • Set the max-age attribute of the STS header to a sufficiently long duration. This is the time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS.
  • Consider adding the 'includeSubDomains' directive if all subdomains are also secured with HTTPS.
  • Consider adding the 'preload' directive if you're sure that the site will use HTTPS permanently in the future. This will allow the site to be included in the HSTS preload list, ensuring that the browser never connects to the domain using an insecure connection.

Compliant code

        from django.http import HttpResponse

def secure_header(request):
    response = HttpResponse()
    response['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'
    return response
        
        

The above code fixes the vulnerability by adding the Strict-Transport-Security HTTP header to the response object. This header is often abbreviated as HSTS, and it tells the browser to only communicate with the server using a secure HTTPS connection.

The max-age attribute is set to 31536000, which is equivalent to one year. This means that the browser will remember for one year that this site should only be accessed using HTTPS.

The includeSubDomains directive is also included. This means that the HSTS policy applies to this domain and all of its subdomains. This is important if you have subdomains and they are also secured with HTTPS.

The preload directive is also included. This means that the site owner agrees to have their domain included in the HSTS preload list. This list is built into browsers and ensures that the browser never connects to the site using an insecure connection, even if it's the very first time the user visits the site. This is a powerful security measure, but it should only be used if you're sure that the site will use HTTPS permanently in the future.

References