Skip to content

Instantly share code, notes, and snippets.

@LeonanCarvalho
Last active August 25, 2022 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LeonanCarvalho/e602f811fef036516532d2a963b28b5a to your computer and use it in GitHub Desktop.
Save LeonanCarvalho/e602f811fef036516532d2a963b28b5a to your computer and use it in GitHub Desktop.
CSRF token Protection, the basics

Cross-site request forgery (CSRF)

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform. It allows an attacker to partly circumvent the same origin policy, which is designed to prevent different websites from interfering with each other.

image

More details at:

<?php
// At top level file you must place token generation and check logic
//It should be bellow the session start
@session_start();
// We must have a Constant to control it, to disable if need (and must not be, but just in case)
defined('DISABLE_CROSS_PROTECTION') or define('DISABLE_CROSS_PROTECTION', false);
// The token can be anything, in this case, just a really random id
//Create/Get the Token
function genToken($force = false){
//To increase security a random key is generated every time
$key = getTokenKey($force);
//Sent $force = true if want to force renew the token.
if($force || (!array_key_exists($key,$_SESSION ) || !$_SESSION[$key])){
$_SESSION[$key] = genHash();
}
return $_SESSION[$key];
}
function getTokenKey($force = false){
//Sent $force = true if want to force renew the token.
if($force || (!array_key_exists('csrf_token_key_name',$_SESSION ) || !$_SESSION['csrf_token_key_name'])){
$_SESSION['csrf_token_key_name'] = genHash();
}
return $_SESSION['csrf_token_key_name'];
}
function genHash(){
return md5(uniqid(mt_rand(), true)."SALT");
}
// This is the process to check the token
function checkToken(){
$key = getTokenKey($force);
//Safe retrive token from the input:
$token = filter_input(INPUT_POST, $key, FILTER_SANITIZE_STRING);
$currentToken = $_SESSION[$key];
genToken(true);
if (!$token || $token !== $currentToken) {
// return 405 http status code, default error response for this case, but you can customize anyway.
header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed');
exit;
}
}
// We only check this for POST method, if you are using GET to "create/update" data its wrong and must be fixed
// Also, in some cases people uses PUT and PATCH in those cases it must be fixed as weel.
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !DISABLE_CROSS_PROTECTION) {
checkToken();
}
<?php
// At top level file you must place token generation and check logic
//It should be bellow the session start
@session_start();
include('csrftokenprotection.php')
//.. all your code goes bellow:
<form action="./buy" method="POST" >
<input type="hidden" name="<?=getTokenKey()?>" value="<?=genToken()?>">
<input type="number" name="qtd" value="1" />
<button class='btn btn-sm btn-xs btn-primary'>Buy</button>
</form>
<html>
<head>
<meta name="x-key" content="<?=getTokenKey()?>" />
<meta name="x-token" content="<?=genToken()?>" />
<script type="text/javascript">
const xKey = "<?=getTokenKey()?>";
// If you wanna use it in a external .js file, you an set a header meta name, for example:
// <meta name="x-key" content="<?=getTokenKey()?>" />
// const xKey = document.querySelector('meta[name="x-key"]')?.content;
const xToken = "<?=genToken()?>"; // Same as xKey
if(xKey && xToken){
// Update all forms with the token:
const forms = document.querySelectorAll('form')
forms.forEach((frm) => {
let input = frm.querySelector(`input[name=${xKey}]`);
if(!input){
input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", xKey);
input.setAttribute("value", xToken);
frm.appendChild(input);
}else{
input.setAttribute("value", xToken);
}
})
}else{
throw 'Invalid CRFS Token implementation'
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment