When should server side sessions be enabled instead of client side
sessions?
I can't think of a situation where you would want something client side other than "user experience".
Session identifiers should always be server side because the server should validate whether the session is valid or not.
Is it safe to put a CSRF-token in a client side cookie, whether it is
encrypted or not?
An anti CSRF-token should contain random generated data, this is a lot "cheaper" than generating an encrypted string, as long as the string is long and random enough.
I do not think that storing the anti CSRF-token in a cookie is sufficient.
I'd recommend creating a system where an anti CSRF-token is submitted from a hidden input field and is transmitted in the header. Both should be checked on the server side.
Here's an example in PHP:
function generateToken($key) {
$token = base64_encode(openssl_random_pseudo_bytes(16));
$_SESSION['csrf_' . $key] = $token;
return $token;
}
function checkToken($key, $value) {
if (!isset($_SESSION['csrf_' . $key]))
return false;
if (!$value)
return false;
if ($_SESSION['csrf_' . $key] !== $value)
return false;
unset($_SESSION['csrf_' . $key]);
return true;
}
if ($_POST and $_POST['action'] == "something")
{
$header_token = apache_request_headers()['X-Anti-Csrf-Token'];
$post_token = $_POST['token'];
$post_token = str_replace(" ", "+", $post_token);
if ($header_token == $post_token)
{
if (checkToken('settings', $post_token))
{
// ok; do something
}
}
else
{
// wrong; do something
}
}
Sending the header before processing it:
<script>
$("#some_div").submit(function(event) {
event.preventDefault();
var $form = $(this),
url = $form.attr('action');
var posting = $.ajax(url, {
type: 'POST',
processData: true,
dataType: "text",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Anti-CSRF-Token', $('#token').val());
}
This piece of code will generate the token and puts it in an hidden input field.
<input id="token" type="hidden" value="<?php echo generateToken('settings'); ?>">