Enabling CSRF Protection

Craft has built-in protection against Cross-Site Request Forgery attacks (CSRF), but you will need to enable it to take advantage of it. You can do that by setting the enableCsrfProtection config setting in your craft/config/general.php file.

'enableCsrfProtection' => true,

Here’s how it works: With CSRF protection enabled, all of your site’s visitors will get a “CRAFT_CSRF_TOKEN” cookie set on their browser, and all POST requests must be accompanied by a POST parameter with a matching name and value (the CSRF Token). If they aren’t, Craft will reject the request with a 400 error.

Craft handles the cookie creation automatically, but it’s up to you to start passing the CSRF Token along with your POST requests.

Updating your HTML forms #

Anywhere you have a <form> with the attribute method="post", you will need to add this inside it:

<input type="hidden" name="{{ craft.config.csrfTokenName }}" value="{{ craft.request.csrfToken }}">

Craft comes with a getCsrfInput() function that gives you the same thing:

<form method="post">
    {{ getCsrfInput() }}
    <!-- ... -->
</form>

Updating your Javascript #

If you have any Javascript code that is creating POST requests, you will need to make sure those are passing the CSRF Token as well. You will need to set the token name and value in Javascript before any scripts are loaded that will need to use it, so your main layout template might look something like this:

<script type="text/javascript">
    window.csrfTokenName = "{{ craft.config.csrfTokenName|e('js') }}";
    window.csrfTokenValue = "{{ craft.request.csrfToken|e('js') }}";
</script>
<script type="text/javascript" src="path/to/script.js"></script>

If you’re using jQuery.ajax() or jQuery.post() to create POST requests over Ajax, you can pass the CSRF Token along with the request by adding it to the object you pass as the function’s data argument:

var data = {
    // ...
};

// Add the CSRF Token
data[csrfTokenName] = csrfTokenValue;

$.post('/some/url', data, function(response, textStatus, jqXHR) {
    // ...
});