Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Protect any origin from CSRF by checking if the Origin/Referer header match the Host header for "unsafe" methods.
/**
* GET and HEAD requests are by definition idempotent and should be handled by the origin as such. Thus, we can safely pass them on without further origin / referer checks.
*/
const safeMethods = ['GET','HEAD'];
const allowedMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'];
addEventListener('fetch', event => {
event.respondWith(verifyAndFetch(event.request))
})
async function verifyAndFetch(request) {
/**
* If the request method is not in our allowed methods, deny the request right away.
*/
if (allowedMethods.indexOf(request.method) === -1) {
return new Response('Sorry, this method is not allowed.',
{ status: 405, statusText: 'Method not allowed' });
}
/**
* If the request is a save method, we can allow it without further checks.
*/
if (safeMethods.indexOf(request.method) !== -1) {
return fetch(request);
}
let host = request.headers.get("Host");
if (host === null) {
return new Response("No host header set", {status: 400, statusText: "Bad Request"});
}
let source = null;
/**
* We prefer using the origin header over the referer header.
*/
if (request.headers.has("Origin")) {
source = request.headers.get("Origin");
} else if (request.headers.has("Referer")) {
source = request.headers.get("Referer");
}
/**
* Let's try to extract the hostname from what we've got.
*
* "null" Origin will fail here.
*/
try {
source = new URL(source).hostname;
}
catch(err) {
source = null;
}
console.log("Source: " + source + " , Target: " + host);
if (source === null) {
return new Response("Sorry, your request has neither Referer nor Origin set and is using a non safe method. Thus, your request has to be blocked because we can't be sure it's not a CSRF attack going on.",
{ status: 403, statusText: 'CSRF Protection' });
}
if (host !== source) {
return new Response("Sorry, your request is a CORS request and we don't allow this here.",
{ status: 403, statusText: 'CSRF Protection' });
}
return fetch(request);
}
@Phara0h

This comment has been minimized.

Copy link

Phara0h commented Jun 10, 2020

What's stopping someone from setting the origin header?

@simonerni

This comment has been minimized.

Copy link
Owner Author

simonerni commented Jun 11, 2020

It's a forbidden header name:
https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name

Of course you can set it by yourself as the attacker, but that's not the point of CSRF protection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.