Created
July 7, 2018 14:52
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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
commented
Jan 22, 2021
via email
•
Thanks for the quick answer! I kinda did a bit of reading and understand it’s some simple form of session keys, thanks for the article!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment