Secure cookie of you web application with PHP or Symfony
Create a cookie in php is easy with function setcookie().
<?php setcookie('user_id', 10, 0, '/', 'orion.dev'); ?> Hello! <script> alert(document.cookie); </script>
<?php setcookie('user_id', 10, 0, '/', 'orion.dev'); var_dump($_COOKIE); ?> Hello! <script> document.cookie = "username=ulrich; expires=Thu, 17 Dec 2020 12:00:00 UTC; path=/"; alert(document.cookie); </script>
<?php setcookie('user_id', 10, 0, '/', 'orion.dev', false, true); var_dump($_COOKIE); ?> Hello! <script> document.cookie = "username=ulrich; expires=Thu, 17 Dec 2020 12:00:00 UTC; path=/"; alert(document.cookie); </script>
In Symfony, we find this option in sessions' configuration in framework section of the config.y(a)ml file. This option is true by default in version 3.x and 4.x but I am not sure this was the case for every versions of symfony 2.
framework: session: cookie_httponly: true
This option can also be set in php.ini configuration file.
If your site is in HTTPS and no longer offers HTTP, this option is for you. It guarantees that the cookie will only be sent if your connection is secure. Hum, this rule only applies in the browser to web server direction and not the other way around. It is up to the developer to verify that connection is secured before sending a cookie to the browser.
But what's the point? This avoids cookie theft via a Man In The Middle attack, since the cookie will be protected during the transfer. This is very important if your application allows users to stay connected, this operation goes through a cookie and from the first request to the server, the browser sends this cookie.
This is the 6th option of the setcookie() function which defaults is false.
setcookie('user_id', 10, 0, '/', 'orion.dev', true, true);
In Symfony, you find this option with http_only but it's false by default on all symfony's version.
framework: session: cookie_httponly: true cookie_secure: true
If you use RememberMe feature in symfony's security, you have to set secure option in security.y(a)ml file.
security: firewalls: main: remember_me: secure: true
They are not well known, but supported by all browsers except those of Microsoft. With prefixes, it's possible to force the browser to not accept a cookie if it's misconfigured. There are two prefixes "__Secure-" and "__Host-".
__Secure- forces the developer to add the secure flag to his cookie, otherwise it will be ignored by the browser.
setcookie('__Secure-user_id', 10, 0, '/', 'orion.dev', true);
__Host- is more restrictive, cookie must have the secure flag but also path to root and blank domain.
setcookie('__Host-user_id', 10, 0, '/', '', true);
You do not see what these prefixes can be used for? Consider them as extra security that will allow you to be alerted (a bug can be an alert!) If you make a mistake in configuring your cookies.
In Symfony, you need to change session name in config.y(a)ml file to add the prefix.
framework: session: cookie_httponly: true cookie_secure: true name: __Secure-sessid
Once again, if you use RememberMe feature, you need to change cookie name in security.y(a)ml file.
security: firewalls: main: remember_me: name: __Secure-REMEMBERME secure: true
This option is also very interesting, it allows to limit (not prevent) CSRF attacks because it tells browsers not to send the cookie if the source query was not made from the site. To put it simply, if I put a Github link here and you click it, the cookie that allows you to get authenticated on github will not be sent. You think it's not user friendly, but if I replace Github with your bank, what do you think?
There are 2 options: lax and strict. As the name suggests "strict" is the most restrictive option. On the other hand "lax" will leave the cookie if the HTTP request is of type GET.
Browsers have a good support of this feature, only Safari is late, but support is planed for next version (mobil & desktop), But Opera has no plan for this feature yet. About PHP, support will be added in next version PHP 7.3
While waiting to migrate on this new version, to take advantage of the support of SameSite, it is necessary to send the cookie via the headers http.
<?php header('Set-Cookie: __Secure-REMEMBERME=5sdf4d65f4; Path=/; Secure; Samesite=lax');
In Symfony, SameSite option will be supported for RememberMe cookie in next version 4.2.
security: firewalls: main: remember_me: name: __SECURE-REMEMBERME secure: true samesite: lax
If you want to check your cookie config and security of your website, I recommend you Mozilla observatory.