Introduction: Cookies are one of the most sensitive items during a user’s session. An authentication cookie is as powerful as a password. Security of these authentication cookies is an important subject. This article demonstrates how we can implement some of the cookie attributes in PHP applications in order to protect cookies from certain attacks. Cookie protection using HTTP Headers: HttpOnly: It is a known fact that, Cross Site Scripting is one of the dangerous vulnerabilities that allows an attacker to steal cookies from the user browser. HttpOnly is introduced to disable the ability to read cookies using external JavaScript. Even if an application is vulnerable to XSS, it is not possible to read cookies when HttpOnly flag is enabled. Let us launch our sample application we used in the previous articles to see how it can be accomplished. First, lets look at the headers from the HTTP response. [plain] HTTP/1.1 200 OK Date: Sun, 12 Apr 2015 15:07:14 GMT Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.20.0 X-Powered-By: PHP/5.6.2 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: PHPSESSID=a2ed2bf468dd811c09bf62521b07a023; path=/ Content-Length: 820 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 [/plain] As we can see, there are no additional flags with the Set-Cookie header and thus an attacker can read this session id if the application is vulnerable to XSS. In order to avoid this, we can implement HttpOnly flag, which enables us to send cookies only over http protocol but not JavaScript. Enabling HttpOnly flag in your application: The sample code snippet below shows a way to set HttpOnly flag in PHP applications. [php]Admin Home


Welcome to Dashboard…

You are logged in as: [logout]

[/php] As we can see in the above piece of code, the following line is used to enable HttpOnly. [plain] ini_set("session.cookie_httponly", "True"); [/plain] Let us now observe the headers and see if HttpOnly is enabled. Below are the response headers intercepted using Burp proxy. [plain] HTTP/1.1 200 OK Date: Sun, 12 Apr 2015 15:03:15 GMT Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.20.0 X-Powered-By: PHP/5.6.2 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: PHPSESSID=36cb82e1d98853f8e250d89be857a0d3; path=/; HttpOnly Content-Length: 820 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 [/plain] As we can see in the headers above, set-cookie header looks as shown below with HttpOnly flag enabled. Set-Cookie: PHPSESSID=36cb82e1d98853f8e250d89be857a0d3; path=/; HttpOnly The real use of this HttpOnly flag is shown below. When an attacker finds an XSS and tries to read the cookies using JavaScript, it won’t work.

As we can see in the above figure, the script we executed is unable to read the cookies though the application is vulnerable to XSS. Secure: The next cookie attribute is “secure”. We often see websites that run on both HTTP and HTTPS. When an application sends its cookies over HTTP, it is possible that they can be hijacked using various ways since they are transmitted in clear text format. “secure” attribute on set-cookie header forces your application to send cookies only over HTTPS. Below is the code snippet that shows how we can use “secure” flag in PHP applications. [php]Admin Home


Welcome to Dashboard…

You are logged in as: [logout]

[/php] The following line from the above code enables secure attribute on the cookies. [plain] ini_set("session.cookie_secure", "True"); [/plain] Let’s look at the response headers to see how it looks like when the above code is run. [plain] HTTP/1.1 200 OK Date: Sun, 12 Apr 2015 15:14:30 GMT Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.20.0 X-Powered-By: PHP/5.6.2 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: PHPSESSID=f95afc96ecb7acc6c288d31f941e682f; path=/; secure Content-Length: 820 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 [/plain] As we can see from the above headers, the secure attribute has been enabled on set-cookie header. In my localhost, I didn’t enable HTTPS support for this application. When we refresh the page, since we do not have HTTPS to send this cookie over a secure channel, the session will not be active anymore over HTTP. This is because, this session cookies are not sent to the server because it requires HTTPS. Killing the session upon closing the browser: It is quite common for the user to close the browsers without clicking the logout button. When we use sensitive applications, it is necessary that the session has to be expired when we close the browser forcibly without logging out. The following lines of code can be used in PHP to accomplish this. [plain] session_set_cookie_params(0); session_start(); [/plain] Assume that we are running the application with the above property set. Now, login to the application and close the browser. If we reopen the page now, the session will be inactive. To check if this property is enabled or not, we can use a cookie editor like “EditThisCookie” in chrome. Login to the application and open “EditThisCookie” extension as shown below.

As we can see in the above figure, “Session” is checked. This ensures that our session will not be active upon closing the browser. The same can also be seen from chrome’s developer tools as shown below.

Following are some other cookie attributes Domain: This attribute gives control on the domains that can access the cookies. Path: it specifies the path of the domain that can have access to the cookie set by the server. Expiration: It specifies when this cookie has to be expired. So that the cookie won’t be valid anymore. We can set all these attributes in PHP applications just with three lines of code as shown below. [plain] ini_set(“session.cookie_secure”, “True”); //secure ini_set(“session.cookie_httponly”, “True”); //httponly session_set_cookie_params(3, ‘/’, ‘.localhost’); //This cookie is valid for 3 seconds (max age) // “/” ensures that this cookie is valid on all //paths of this domain // since the domain is prefixed with dot, this //cookie is accessible from all the subdomains. session_start(); [/plain] When we load the page with the above attributes, the response headers will be as shown below. [plain] HTTP/1.1 200 OK Date: Thu, 30 Apr 2015 03:04:11 GMT Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.20.0 X-Powered-By: PHP/5.6.2 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: PHPSESSID=f4d99777d9810bfedb6869acd556bc66; expires=Thu, 30-Apr-2015 03:04:14 GMT; Max-Age=3; path=/; domain=.localhost; secure; HttpOnly X-XSS-Protection: 1 Content-Security-Policy: script-src ‘self’ Content-Length: 820 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 [/plain] In this article, we have seen how cookies can be secured using various attributes available with set-cookie response header. Though, these concepts can drastically improve the security of a web application, we cant solely depend on those headers to protect an application, rather we should consider using them to add additional layer of security.