CSRF tokens and CSRF headers
Adding a custom request header to 'unsafe' outgoing AJAX requests (e.g. POST requests) adds some additional protection against CSRF attacks. Article here: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#custom-request-headers
The principle is that, due to browsers' Same-Origin policies, the header will only reach the server if the website it came from was within the same domain. This protection layer is fairly easy to implement.
Here, as an example, is how Deserted Chateau handles adding a custom request header to AJAX requests:
var csrf_token = $('meta[name="deserted-chateau-csrf-token"]').attr('content');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS)$/.test(method));
}
// Set request headers and CSRF tokens where needed
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("deserted-chateau-anti-csrf-token", csrf_token);
}
},
headers: {'deserted-chateau-anti-csrf-header': 'With your face, like a swindled partridge'},
});
The value, and indeed name, of the header don't really matter (other than that you should avoid picking a name that might conflict with other HTTP headers). In case you were wondering why the CSRF header here has the value it does... https://www.youtube.com/watch?v=RyKJMs9IOds
On the server, you then need to check that this HTTP header is present in any request where an 'unsafe' request was made (e.g. POST requests). An example function in PHP would look like this:
public static function verifyCSRFHeader() {
$csrfHeaderValue = $_SERVER['HTTP_DESERTED_CHATEAU_ANTI_CSRF_HEADER'];
$validHeader = ($csrfHeaderValue === "With your face, like a swindled partridge");
if (!$validHeader) {
// Log that an invalid header was received, if desired
}
// Return whether the header was present and valid; the calling function can then decide what to do
return $validHeader;
}
Note the extra HTTP_ in the string given to the $_SERVER array, and that it has all dashes replaced with underscores.