Sensitive information sent via URL parameters - Python

Sensitive information sent via URL parameters - Python

Need

Protection of sensitive information during transmission

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
from django.views import View

class SensitiveDataView(View):
    def get(self, request, *args, **kwargs):
        username = request.GET.get('username')
        password = request.GET.get('password')
        return HttpResponse(f"Username: {username}, Password: {password}")
        
        

The above Python code is a Django view that retrieves sensitive data (username and password) directly from the URL parameters using the GET method. This is a security vulnerability as the sensitive data is exposed in the URL.

1. Stored in clear text in the browser history: The browser history will store the full URL including the parameters. This means that the sensitive data (username and password) will be stored in clear text in the browser history.

2. Sent to external sites via the referrer HTTP header: If a user navigates to another site from the page that has the sensitive data in the URL, the new site may have access to the referrer URL which includes the sensitive data.

3. Sent to external sites via the search bar if the browser interprets the URL as a query: If a user accidentally types the URL into a search bar instead of the address bar, the search engine may interpret the URL parameters as a search query, thus exposing the sensitive data.

4. Visible to scripts running on the browser that may belong to third-parties: Any scripts running on the browser (such as third-party analytics or advertising scripts) will have access to the full URL, including the sensitive data in the parameters. This could lead to unauthorized access or data leaks.

Steps

  • Switch from using the GET method to the POST method for sending sensitive data.
  • Ensure that sensitive data is not included in the URL parameters.
  • Use Django's built-in forms for handling user input and validation.
  • Store sensitive data securely, such as passwords, using hashing and salting techniques.
  • Implement HTTPS to encrypt the data during transmission.

Compliant code

        from django import forms
from django.http import HttpResponse
from django.views import View
from django.contrib.auth.hashers import make_password

class LoginForm(forms.Form):
    username = forms.CharField(max_length=100)
    password = forms.CharField(widget=forms.PasswordInput)

class SensitiveDataView(View):
    form_class = LoginForm

    def get(self, request, *args, **kwargs):
        form = self.form_class()
        return render(request, 'login.html', {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = make_password(form.cleaned_data.get('password'))
            return HttpResponse(f"Username: {username}, Password: {password}")
        else:
            return HttpResponse("Invalid form data")
        
        

The above code fixes the vulnerability by switching from the GET method to the POST method for sending sensitive data. This ensures that sensitive data is not included in the URL parameters, which can be stored in clear text in the browser history, sent to external sites via the referrer HTTP header, or visible to scripts running on the browser that may belong to third-parties.

A Django form, LoginForm, is used to handle user input and validation. This form includes fields for the username and password. The password field uses a PasswordInput widget, which renders an HTML input element with type password. This means that the password input will be obscured on the client side.

In the SensitiveDataView, the get method renders a template, 'login.html', with the login form. The post method handles form submission. It validates the form data and, if valid, retrieves the cleaned data. The password is hashed using Django's make_password function before it is used. This ensures that the password is stored securely.

Finally, it is recommended to implement HTTPS to encrypt the data during transmission. This is not shown in the code as it is typically handled at the server or network level, not in the application code.

References