7

From an information security perspective, when should server side sessions be enabled instead of client side sessions?

From what I gather, "secure client side sessions" are cookies that contain data signed in such a way that the user can "look" at their contents, but cannot modify them without the server knowing. I'm a bit confused as to whether this implies that the contents of the cookie are encrypted, or that the contents are human readable. Flask, for example, encrypts the data. If the data is encrypted, than in what circumstances would it not be safe to store session data in the cookie? For example, is it safe to put a csrf-token in a client side cookie, whether it is encrypted or not?

On the other hand, a "server side session" has two parts: a cookie containing only a session ID, and a database entry containing the session ID and the data. In this implementation, the user cannot access the session data.

  • Flask does not encrypt the Cookie (source). Rather it is Base64 encoded with a Signature (generated with the flask SECRET_KEY) which makes it possible for the server to detect modifications. Do not store any sensitive data there which includes CSRF Tokens. Rather use a hidden input field the way Flask WTF does. In any case I would recommend using such package instead of implementing CSRF Protection on your own. – matt3o Aug 2 '16 at 14:40
  • @user3771575 I stand corrected! Thanks for the source. The solution for Flask based solutions is to encrypt the session data first. – Matthew Moisen Aug 2 '16 at 18:48
7

For example, is it safe to put a csrf-token in a client side cookie, whether it is encrypted or not?

Yes. OWASP calls this method Double Submit Cookies. I have never seen it in practice though.

The reason this is safe is that CSRF tokens are temporary values. For example, if you would store an encrypted password in a client side session, that would be pretty bad (depending on the key and encryption algo). An attacker may be able to steal it, decrypt it, and then have the users password. For the CSRF token, an attacker gains nothing. Additionally, it doesn't affect server security if an attacker or user changes the cookie, all that will happen is that the token doesn't work.

in what circumstances would it not be safe to store session data in the cookie?

There are two things to worry about here:

  • A user or attacker may change data in the cookie and the server would have no idea that this happened, accepting the changed data (for example, it may contain a value such as isAdmin:0, which may be changed to isAdmin:1).
  • The cookie could contain sensitive information which a user or attacker may read out

To solve the first point, a MAC could be used, to solve the second point, the cookie data should be encrypted.

Before you create client side sessions, you should ask yourself if you really need it (which may be the case if you have multiple servers which need to share the same session state, eg for scalability reasons). Session data is traditionally handled server side for a reason: It contains data that the client should not be able to read or change. That's easiest to do by just not sending it to the client.

Setting up a complex system to store session data client side is difficult, and a lot may go wrong doing it. If it's not necessary, just store the data server side.

  • In the flask code, session data is stored as a MAC, and throws a bad request if the cookie is tampered with. Likewise, session data is encrypted. The flask-wtf extension handles CRSF protection, and it stores the CSRF token inside of the session (which is stored in the cookie). On each form submission, it compares the form-provided csrf token and the session's csrf token. I believe this is the "synchronizer token pattern" – Matthew Moisen Feb 25 '16 at 20:21
  • What I would be concerned about is if another website could access a user's cookie, and therefore get the CSRF token. – Matthew Moisen Feb 25 '16 at 20:23
  • At any rate, if one uses a framework which stores session data as a MAC in a cookie, and encrypts the session data, why not go ahead and store session data in a cookie? – Matthew Moisen Feb 25 '16 at 20:23
  • @MatthewMoisen The synchronizer token pattern is the normally used approach to CSRF (the token is stored in a session, not in the cookie). If the token is encrypted, I guess you could make a case that that is still a session, and so it's the synchronizer token pattern, not the double submit cookies pattern (which sends the token in a cookie, but unencrypted). – tim Feb 25 '16 at 20:41
  • @MatthewMoisen The case against client-side session would be 1) it provides an (often) unneeded additional attack surface 2) If the session does contain sensitive information, an attacker may be able to bruteforce it (provided they have enough time and resources) 4) an attacker may be able to obtain the MAC key and thus submit changed data 5) it causes network overhead (session data is larger than a session id, and when the data changes, additional headers have to be send). – tim Feb 25 '16 at 20:43
1

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'); ?>">
  • 1
    "I can't think of a situation where you would want something client side other than "user experience"." Keeping the session server-side makes it hard to scale your application horizontally. If you retrieve the session from the database every request, you will need to cluster and/or shard your database, each of which presents its own problems. If you cache the session in memory, you tie the session to the server instance, and interfere with load-balancing. – Code Bling Nov 5 '16 at 7:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.