Skip to main content

XS-Leaks

Need

Protection of sensitive user information from being leaked through browser side-channels

Context

  • Usage of Python 3 for writing and executing Python code
  • Usage of Django for web development with Python

Description

Non compliant code

from django.http import HttpResponse

def user_info(request):
if request.method == 'GET':
user = request.GET['user']
data = fetch_sensitive_data(user)
return HttpResponse(data)

In the above Python Django code, the function user_info() is vulnerable to cross-site leaks (XS-Leaks). The function fetches sensitive data based on the 'user' parameter from the GET request. This means that an attacker can potentially craft a GET request with a specific 'user' parameter to extract sensitive information.

In this scenario, the sensitive data is directly returned as an HTTP response. This sensitive data can be leaked to an attacker through various browser side-channels. For example, an attacker could measure the size of the response to infer information about the user, or use timing attacks to determine the time taken to process the request and correlate it with the user's information.

The vulnerability lies in the fact that there is no proper validation or sanitization of the 'user' parameter and the sensitive data is directly exposed in the HTTP response. This can lead to potential information disclosure and privacy violation.

Steps

  • Use the POST method instead of GET for sensitive data. GET parameters are logged in browser history and server logs, which can lead to information leakage.
  • Implement Cross-Origin Resource Sharing (CORS) policy to restrict who can access the data.
  • Use the SameSite attribute for cookies to prevent them from being sent in cross-site requests.
  • Use the HTTPOnly attribute for cookies to prevent them from being accessed through client-side scripts.
  • Implement Content Security Policy (CSP) to prevent unauthorized inline scripts from running.
  • Use HTTPS to encrypt data in transit and prevent man-in-the-middle attacks.

Compliant code

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.middleware.csrf import get_token

@csrf_exempt
def user_info(request):
if request.method == 'POST':
user = request.POST['user']
data = fetch_sensitive_data(user)
response = HttpResponse(data)
response['Content-Security-Policy'] = "default-src 'self'"
response['Access-Control-Allow-Origin'] = 'https://trustedwebsite.com'
response.set_cookie('sensitive_cookie', 'cookie_value', secure=True, httponly=True, samesite='Strict')
return response

The updated code now uses the POST method instead of GET for sensitive data. This is because GET parameters are logged in browser history and server logs, which can lead to information leakage.

The @csrf_exempt decorator is used to exempt this particular view from the CSRF protection. However, it is generally recommended to use CSRF protection, especially for views that handle POST requests.

The Content-Security-Policy header is set to only allow scripts, styles, and images from the same origin. This prevents unauthorized inline scripts from running.

The Access-Control-Allow-Origin header is set to a trusted website. This is a part of the Cross-Origin Resource Sharing (CORS) policy, which restricts who can access the data.

The set_cookie method is used to set a cookie with the secure, httponly, and samesite attributes. The secure attribute ensures that the cookie is only sent over HTTPS, the httponly attribute prevents the cookie from being accessed through client-side scripts, and the samesite attribute prevents the cookie from being sent in cross-site requests.

Finally, it is recommended to use HTTPS to encrypt data in transit and prevent man-in-the-middle attacks. This is not shown in the code as it is usually configured in the web server or load balancer.

References