TL;DR I need to protect my form from CSRF attacks and I want to use ReactJS for the frontend and Flask/Flask-WTF for the backend.
I’m refactoring a website built with Python, Flask, and Flask-WTF for forms and I want to use React for the frontend rather than Jinja2 through PyPugjs. I’m using Flask-WTF to render the forms and it takes care of the CSRF tokens and such. I know how to make a form with React but how do I get CSRF protection?
Right now my form rendering looks like this: (uses Pug)
mixin render_form(form, id='', action='Submit')
form(method='POST', action='', id=id)
=form.csrf_token
each field in form
fieldset
if field.errors
each error in field.errors
.notification.error
#{error}
#{field(placeholder=field.label.text)}
button(type='submit') #{action}
To enable CSRF protection globally for a Flask app, register the CSRFProtect extension. CSRF protection requires a secret key to securely sign the token. By default this will use the Flask app's SECRET_KEY . If you'd like to use a separate token you can set WTF_CSRF_SECRET_KEY .
Luckily, it's easy to implement CSRF protection in React. You only have to store the CSRF token in your React app and generate relevant headers to send along with the request to the server. The server will quarantine all CSRF requests.
Cross-site request forgery (CSRF) is a web security liability. That permits an attacker to convince users to do actions that they do not offer to do. It lets an assailant to partially avoid the same origin policy that is planned to prevent diverse websites from interfering with each other.
WTF stands for WT Forms which is intended to provide the interactive user interface for the user. The WTF is a built-in module of the flask which provides an alternative way of designing forms in the flask web applications.
You'll need to send the csrf token as the header X-CSRFToken
when you POST the form. See their docs here: http://flask-wtf.readthedocs.io/en/stable/csrf.html#javascript-requests
Their example w/ POSTing via jQuery sets the X-CSRFToken
before sending any POST/PUT/DELETE ajax requests:
<script type="text/javascript">
var csrf_token = "{{ csrf_token() }}";
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrf_token);
}
}
});
</script>
Depending on what library you're using to send the form POSTs back to the server, your implementation of setting the header X-CSRFToken
will be different.
You can throw {{ csrf_token() }} in a meta tag in index.html
<meta id="csrf-token" content={{csrf_token()}}>
then when you wanna post/fetch, just add it to ur headers with
export const post = (path, data={}) => {
const options = {
method: 'POST',
headers: {
// 'Accept': 'application/json; charset=utf-8',
// 'Content-Type': 'application/json; charset=utf-8',
// 'Cache': 'no-cache',
// 'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.getElementById("csrf-token").getAttribute("content")
},
body: data
};
return fetch(path, options);
}
p.s. this still feels hacky and I'm still looking for a more reacty way
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With