Skillnaden mellan att skicka något som GET och POST är hur man öppnar formuläret.
<form action="URL" method="get">
<form action="URL" method="post">
Inuti form taggen placerar man CSRF token:
<form action="URL" method="post">
<input type="hidden" name="csrf_token_name" value="ajudiasdjsaidsaud8da878">
...
</form>
Går självklart att använda med GET också, om ni nu använder <a> taggar för att "Lägga till i kundkorgen". Det ser dock väldigt fult ut.
<a href="produkter.php?action=add&csrf_token_name=ajudiasdjsaidsaud8da878">Lägg till i kundkorgen</a>
<form action="URL" method="get">
<input type="hidden" name="csrf_token_name" value="ajudiasdjsaidsaud8da878">
...
</form>
Ni hämtar sedan csrf_token_name med hjälp utav $_GET eller $_POST och validerar den.
$valid = isset($_GET['csrf_token_name'], $_SESSION['csrf_token_name'])
&& hash_equals($_GET['csrf_token_name'], $_SESSION['csrf_token_name']);
$valid = isset($_POST['csrf_token_name'], $_SESSION['csrf_token_name'])
&& hash_equals($_POST['csrf_token_name'], $_SESSION['csrf_token_name']);
Själva token måste genereras på ett säkert sätt och kan göras tillsammans med följande. (Codeigniter)
/**
* Get random bytes
*
* @param int $length Output length
* @return string
*/
public function get_random_bytes($length)
{
if (empty($length) OR ! ctype_digit((string) $length))
{
return FALSE;
}
if (function_exists('random_bytes'))
{
try
{
// The cast is required to avoid TypeError
return random_bytes((int) $length);
}
catch (Exception $e)
{
// If random_bytes() can't do the job, we can't either ...
// There's no point in using fallbacks.
log_message('error', $e->getMessage());
return FALSE;
}
}
// Unfortunately, none of the following PRNGs is guaranteed to exist ...
if (defined('MCRYPT_DEV_URANDOM') && ($output = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)) !== FALSE)
{
return $output;
}
if (is_readable('/dev/urandom') && ($fp = fopen('/dev/urandom', 'rb')) !== FALSE)
{
// Try not to waste entropy ...
is_php('5.4') && stream_set_chunk_size($fp, $length);
$output = fread($fp, $length);
fclose($fp);
if ($output !== FALSE)
{
return $output;
}
}
if (function_exists('openssl_random_pseudo_bytes'))
{
return openssl_random_pseudo_bytes($length);
}
return FALSE;
}
Och används såhär:
$rand = $this->get_random_bytes(16);
$rand = ($rand === FALSE)
? md5(uniqid(mt_rand(), TRUE))
: bin2hex($rand);
$_SESSION['csrf_token_name'] = $rand;
Har ni mycket AJAX på sidan eller inte vill smutsa ner era formulär/länkar så är det Set-Cookie istället som gäller. Då jQuery m.m kan hämta upp den. Sätts med hjälp av setcookie() på alla sidor. http://php.net/manual/en/function.setcookie.php
Då behöver man ändra lite på $valid som jag skrev ovan, från $_SESSION till $_COOKIE.
Set-Cookie:csrf_token_name=ajudiasdjsaidsaud8da878; path=/; httponly