Skip to content

Instantly share code, notes, and snippets.

@simonerni
Created July 7, 2018 14:52
Show Gist options
  • Save simonerni/3501b8de6320ac37398d08d9d2d08561 to your computer and use it in GitHub Desktop.
Save simonerni/3501b8de6320ac37398d08d9d2d08561 to your computer and use it in GitHub Desktop.
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);
}
@Macleykun
Copy link

Macleykun commented Jan 22, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment