Last active
February 21, 2020 10:58
-
-
Save danielbeardsley/6060418 to your computer and use it in GitHub Desktop.
Dynamically add CSRF protection <input>s to each form on the page immediately before it's submitted. This code uses MooTools, though it would be trivial to remove that dependency or swap with jQuery.
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
var CSRF = (function() { | |
window.addEvent('domready', function() { | |
/** | |
* Setup triggers on the .submit() function and the `submit` event so we | |
* can add csrf inputs immediately before the form is submitted. | |
*/ | |
$$('form').each(function(form) { | |
// Ensure all forms submitted via a traditional 'submit' button have | |
// an up-to-date CSRF input | |
form.addEvent('submit', function() { | |
ensureFormHasCSRFFormField(form); | |
}); | |
// Ensure all forms submitted via form.submit() have an up-to-date CSRF | |
// input | |
var oldSubmit = form.submit; | |
// Wrap the default submit() function with our own | |
form.submit = function () { | |
ensureFormHasCSRFFormField(form); | |
return oldSubmit.apply(form, Array.from(arguments)); | |
} | |
}); | |
}); | |
/** | |
* Generate a new token and store it in the cookie | |
*/ | |
function resetToken() { | |
/** | |
* random() generates a number [0..1] so the first two chars are always | |
*'0.' no matter what the base. | |
*/ | |
var token = Math.random().toString(36).substring(2,12); // 10 char string | |
// 30 days is pretty arbitrary, it could be 3 minutes or 3 years. | |
Cookie.write('csrf', token, { duration: 30 }); // 30 days | |
return token; | |
} | |
/** | |
* Ensure the provided Form element has a CSRF token | |
* input who's value is up to date. | |
*/ | |
function ensureFormHasCSRFFormField(form) { | |
csrfInputForForm(form).set('value', CSRF.get()); | |
} | |
/** | |
* Return the csrf input element for the given form or give it one. | |
*/ | |
function csrfInputForForm(form) { | |
var csrfInput = form.getElement('.csrf'); | |
if (!csrfInput) { | |
csrfInput = CSRF.formField(); | |
form.grab(csrfInput); | |
} | |
return csrfInput; | |
} | |
return { | |
/** | |
* ## CSRF.get() | |
* | |
* Read the value from the cookie or create and return one | |
* if it doesn't exist | |
*/ | |
get: function() { | |
return Cookie.read('csrf') || resetToken(); | |
}, | |
/** | |
* Returns a new hidden input field with the CSRF token as a value. | |
* Used when dynamically creating forms. | |
*/ | |
formField: function() { | |
return new Element("input", { | |
type: 'hidden', | |
name: 'csrf', | |
'class': 'csrf', | |
value: CSRF.get() | |
}); | |
} | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment