How to enable CSRF protection in the Python / Flask app?
Tags: python, webdev, security, beginners
Published: 2020-05-17 18:24:58

<h3>What is CSRF?</h3>

**CSRF** stands for **C**ross **S**ite **R**equest **F**orgery. It is a security vulnerability that forces an end user to __unknowingly__ let attackers perform malicious actions on the end user's behalf within the sensitive website they are currently authenticated into such as their bank or social media account. 

In order to perform these type of attacks, attackers would typically know the end user’s activity along with CSRF vulnerable websites the end user has access to. If the end user happens to visit the attacker’s site while authenticated to the website (such as user's bank account), the attacker could perform malicious action on the end user's behalf potentially damaging the user’s possession in the their authenticated website.  

<h3>How to prevent CSRF attacks?</h3> 

* GET requests should only be used for retrieving information from the web application. If GET requests are used for state changing operations such as transfer of money from the user’s account, transfer detail parameters would be part of the URL: `http://bank.com/transfer.do?acct=BOB&amount=100`. These type of GET requests are easier for attackers to forge.

* Sensitive / state changing actions within the application should only be performed with POST requests with a form submission mechanism. 

* State changing requests should be mandated with a csrf token that is generated by the server and sent to the end user’s browser. Typically these tokens would be hard to guess by the attacker. Here is an example of generated csrf token:   
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jun68tyc4l10khyzvyzm.png)

<h3>How to enable CSRF protection in the Flask app?</h3>   
Flask framework does not have csrf protection out of the box. However, csrf protection could be enabled with Flask-WTF extension.

* Use below command to globally enable csrf protection within the application:
```python
from flask_wtf.csrf import CSRFProtect

csrf = CSRFProtect(app)
```
* CSRF protection requires a secret key to securely sign the token. By default Flask app’s SECRET_KEY is used for this secure signing. If desired, a separate key called WTF_CSRF_SECRET_KEY could be configured for this purpose.

* Views using FlaskForms are automatically enabled with csrf protection. CSRF token should be added like normal field in FlaskForm’s template:
```html
<form method="post">
    {{ form.csrf_token }}
</form>
```
* If the view template uses normal HTML form, CSRF token should be added as a hidden field: `<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>`

* If the application uses AJAX request, CSRF token should be added using the X-CSRFToken header.
 
* Although not recommended, some routes could be exempted from the csrf protection using `@csrf.exempt` decorator.

<h3>Conclusion</h3>
Since CSRF vulnerability is one of OWASP’s top 10 vulnerabilities, developers building web applications using Flask framework should ensure they enable CSRF protection using Flask-WTF extension.

<h5>References:</h5>
* https://owasp.org/www-community/attacks/csrf
* https://flask-wtf.readthedocs.io/en/v0.14.2/csrf.html