Mitigating XSS and CSRF Vulnerabilities in Django Applications
Preventing XSS (Cross-Site Scripting)
Caution with safe and mark_safe
When Django templates render variables, they escape HTML by default to prevent script injection. Using the safe filter or mark_safe() function disables this protection.
Example:
# Backend code
from django.utils.safestring import mark_safe
user_input = "<a href='#'>Click here</a>"
safe_output = mark_safe(user_input)
<!-- Template usage -->
{{ safe_output|safe }}
This renders the anchor tag directly, potentially allowing malicious scripts if the input is untrusted.
Input Validation with BeautifulSoup
To safely handle HTML input, validate and sanitize it before processing. BeautifulSoup can parse and clean HTML content.
Example:
from bs4 import BeautifulSoup
def sanitize_html(raw_html):
soup = BeautifulSoup(raw_html, 'html.parser')
# Remove potentially dangerous tags
for tag in soup.find_all(['script', 'iframe']):
tag.decompose()
return str(soup)
Preventing CSRF (Cross-Site Request Forgery)
Form-Based Protection
Django's CSRF middleware requires including a token in forms for POST requests.
Example form template:
<form method="post">
{% csrf_token %}
<label>Username: <input type="text" name="username"></label>
<label>Password: <input type="password" name="password"></label>
<button type="submit">Submit</button>
</form>
AJAX Request Handling
Method 1: Include Token in Request Data
$(".submit-btn").on("click", function() {
let tokenValue = $("input[name='csrfmiddlewaretoken']").val();
$.ajax({
url: "/process-data/",
method: "POST",
data: {
username: $("#username-field").val(),
csrfmiddlewaretoken: tokenValue
},
success: function(response) {
console.log("Success:", response);
}
});
});
Method 2: Use Cookie with Custom Header
$(".submit-btn").on("click", function() {
let csrfToken = getCookie("csrftoken");
$.ajax({
url: "/process-data/",
method: "POST",
headers: {"X-CSRFToken": csrfToken},
data: {username: $("#username-field").val()},
success: function(response) {
console.log("Success:", response);
}
});
});
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
Backend Configuration
Function-Based Views
Use decorators to control CSRF protetcion at the view level.
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt # Disables CSRF check for this view
def unprotected_view(request):
if request.method == "POST":
return HttpResponse("POST received")
return HttpResponse("GET request")
@csrf_protect # Enforces CSRF check (default in Django)
def protected_view(request):
return HttpResponse("CSRF-protected response")
Class-Based Views
Apply decorators to class methods using method_decorator.
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name="dispatch")
class ExampleView(View):
def get(self, request):
return HttpResponse("GET method")
def post(self, request):
return HttpResponse("POST method")