-
Notifications
You must be signed in to change notification settings - Fork 0
tech02 python
Updated: 08/23/2017
Cross site request forgeries is where a malicious site is able to cause a user's browser to make POST requests to our servers hijacking a submitted form. CSRF attacks can be particuluar damaging for sites that have user accounts, users login, and where data on the server can be modified by that user. Additional CSRF information can be found here.
Csrf protection is enabled by default in django, where it is set in settings.py (or for qed settings_docker.py) under MIDDLEWARE_CLASSES as 'django.middleware.csrf.CsrfViewMiddleware'. Complete Django CSRF protection documentation can be found here.
If csrf protection is enabled, the token can be found in the request object under cookies. Even though the value of the csrf token is visible to a user, the token can not be hijacked because the token has a random salt added and then is scrambled.
The two primary cases where csrf tokens are used are in html form submissions and ajax post calls.
- Insert '{% csrf_token %}' inside the form tags of your template file. Sample code from templates_qed/hms/04hms_input_start_drupal.html (lines 47-48)
<form method="post" action="/hms/{{ MODEL }}/output/" name="input_table">
{% csrf_token %}
Django will know to insert a hidden field into the form containing the csrf token.
- For django to know what the csrf_token is, the request object has to be passed to the template when it is rendered in django. Sample code from hms_app/models/hydrology/hydrology_inputs.py (lines 19-24)
html += render_to_string('04hms_input_start_drupal.html',
{
'MODEL': model,
'SUBMODEL': submodel,
},
request=request)
If this does not correct a csrf missing error, ensure that the request object you are passing into your render function contains the csrf cookie.
- On the template page, the csrf cookie will need to be extracted from the cookies. Using the follow function:
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
The csrftoken variable needs to be a 'global' variable so that it can be assigned to the appropriate header value of your ajax call.
The following code can be placed inside the
beforeSend: function (xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
These two sections of code will take the csrf token from the requests.Cookies and insert the token into the request header for your ajax calls.
- Just like the html form case, the request object needs to be provided to the render function for that template page so that django can build the html page with the csrf cookie.
- Import the following into your .py that the url is pointing to, the function receiving the POST request.
from django.views.decorators.csrf import csrf_exempt
- Decorate your function with
@csrf_exempt
Example code can be found in cts_app/cts_api/views.py