ESCT: Part 6 - Cookie Security
Mix.install([
{:grading_client, path: "#{__DIR__}/grading_client"},
:phoenix,
:plug
])
alias Phoenix.ConnTest
alias Plug
conn = ConnTest.build_conn()
:ok
Introduction
An HTTP cookie (web cookie, browser cookie) is a small piece of data that a server sends to a user’s web browser via HTTP headers or set via JavaScript. The browser may store the cookie and send it back to the same server with later requests.
Cookies are mainly used for three purposes:
- Session management - Logins, shopping carts, game scores, or anything else the server should remember
- Personalization - User preferences, themes, and other settings
- Tracking - Recording and analyzing user behavior
Tables of Contents
Ingredients of a Cookie
Attributes
HTTP Cookies have attributes that influence how they are managed by the client(s) that consumes them. It is through the values set within these attributes that makes or breaks their security.
Secure
Cookies with the Secure attribute ensures that they will only be transmitted over HTTPS.
The Secure attribute only protects the confidentiality of a cookie against Man in the Middle attackers - there is no integrity protection. E.g. An attacker could still edit a cookie in transit, but not read it
HttpOnly
This attribute disables the cookie from being accessed via client-side JavaScript. This is the number one cookie protection against Cross-Site Scripting.
HttpOnly enabled cookies can still be replaced by overflowing the cookie jar from JavaScript
Domain
The Domain attribute specifies which hosts can receive a cookie.
- If unspecified, the attribute defaults to the same host that set the cookie, excluding subdomains.
- If Domain is specified, then subdomains are always included.
Therefore, specifying Domain is less restrictive than omitting it. However, it can be helpful when subdomains need to share information about a user.
For example, if you set Domain=mozilla.org
, cookies are available on subdomains like developer.mozilla.org
.
Path
The Path attribute indicates a URL path that must exist in the requested URL in order to send the Cookie header. The %x2F
(“/“) character is considered a directory separator, and subdirectories match as well.
For example, if you set Path=/docs
, these request paths match:
-
/docs
-
/docs/
-
/docs/Web/
-
/docs/Web/HTTP
But these request paths don’t:
-
/
-
/docsets
-
/fr/docs
SameSite
The SameSite attribute lets servers specify whether/when cookies are sent with cross-site requests. This provides some protection against Cross-Site Request Forgery attacks (CSRF).
There are three different settings for the SameSite attribute:
- Strict - The cookie is only sent to the site where it originated.
-
Lax - Similar to “Strict” except that cookies are sent when the user navigates to the cookie’s origin site.
- E.g. Following a link from an external site.
- None - specifies that cookies are sent on both originating and cross-site requests, but only in secure contexts (i.e., if SameSite=None then the Secure attribute must also be set).
If no SameSite attribute is set, the cookie is treated as Lax.
Prefixes
Because of the design of the cookie mechanism, a server can’t confirm that a cookie was set from a secure origin or even tell where a cookie was originally set.
A vulnerable application on a subdomain can set a cookie with the Domain attribute, which gives access to that cookie on all other subdomains.
However, you can use Cookie Prefixes to assert specific facts about the cookie. The browser will reject cookies with these prefixes if they don’t comply with their restrictions.
Two prefixes are available:
__Host-
If a cookie name has this prefix, it’s accepted in a Set-Cookie
header only if it meets all these conditions:
- It’s also marked with the “Secure” attribute
- It was sent from a secure origin
- It does not include a Domain attribute
-
It has the Path attribute set to
/
This way, these cookies can be seen as “domain-locked”.
__Secure-
If a cookie name has this prefix, it’s accepted in a Set-Cookie header only if it meets all these conditions:
- It’s marked with the Secure attribute
- It was sent from a secure origin.
This is weaker than the __Host- prefix.
Strict Secure Cookies
This adds restrictions on cookies marked with the “Secure” attribute. Currently, Secure cookies cannot be accessed by insecure (e.g. HTTP) origins. However, insecure origins can still add Secure cookies, delete them, or indirectly evict them. This feature modifies the cookie jar so that insecure origins cannot in any way touch Secure cookies. This does leave a carve out for cookie eviction, which still may cause the deletion of Secure cookies, but only after all non-Secure cookies are evicted.
The Perfect Cookie
Ooie-gooie and fresh out of the oven, perfectly golden brown. Here are some attributes that would go into making one of the most secure cookies out there!
-
Cookie Prefix:
__Host
-
Path:
/
-
Secure:
True
-
HttpOnly:
True
-
SameSite:
Strict
Ideally the cookie is also cryptographically signed or encrypted, but how that is done is typically up to the implementation.
Signed Cookies
Signed cookies are an alternative to signed URLs. Signed cookies protect access when separately signing tens or hundreds of URLs for each user isn’t feasible in your application. Signed cookies let you do the following:
- Authorize a user and provide them with a time-limited token for accessing your protected content (instead of signing each URL).
- Scope the user’s access to a specific URL prefix, such as https://media.example.com/videos/, and grant the authorized user access to protected content within that URL prefix only.
- Keep your URLs and media manifests unchanged, simplifying your packaging pipeline and improving cacheability.
Preventing Misuse of Signed Cookies
If you specify the Domain parameter in a Set-Cookie header, specify the most precise value possible to reduce the potential for access by someone with the same root domain name. For example, app.example.com is preferable to example.com, especially when you don’t control example.com. This helps prevent someone from accessing your content from www.example.com. To help prevent this type of attack, do the following:
- Exclude the Expires and Max-Age cookie attributes, so that the Set-Cookie header creates a session cookie. Session cookies are automatically deleted when the user closes the browser, which reduces the possibility of someone getting unauthorized access to your content.
- When possible, use a custom policy and include the IP address of the viewer.
- Specify the shortest reasonable expiration time based on how long you want users to have access to your content.
Encrypted Cookies
Encrypting your cookies adds a layer of security since the browser client can not decrypt the data. With this, server side encryption makes cookies only meaningful to the intended back end application, and adds protection so that clients can not sniff the cookies.
The encryption you use can be a one-way lookup of the cookie value. It is possible to use the encrypted value as the key to lookup data on the server. This means there is no need to take the cookie value and assume it is valid on the server. The web server can use the encrypted value to confirm what it knows about the client from the session. This one-way look up of encrypted cookie values adds an extra layer of protection.
For instance, in the next section the Plug library gives you the ability to perform those actions within the put_resp_cookie/4
function call. But if you store JSON Web Tokens (JWTs) as the value of your cookie, you can achieve similar signature results through the JWTs themselves.
Resources
- https://cloud.google.com/cdn/docs/using-signed-cookies#:~:text=Signed%20cookies%20give%20time%2Dlimited,t%20feasible%20in%20your%20application
- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html
Elixir Phoenix Cookies
In the Phoenix Framework, you would use functionality found within the Plug library to set a cookie.
Quiz
Given the “Perfect Cookie” outlined above, how would you assign that cookie using the Plug library?
Fill out the put_resp_cookie/4
function arguments with the settings outlined in the previous section, no other code changes should be necessary.
cookie_name = "CHANGE_ME_TOO"
conn
|> Plug.Conn.put_resp_cookie(
cookie_name,
<<42::16>>
# domain: ,
# path: ,
# secure: ,
# http_only: ,
# same_site:
)
Data Privacy For Cookies
Storing personal information
While cookies by themselves can not dig and research your information, they do store personal information in at least 2 ways: form information and ad tracking.
Personal information is not generated by the cookies themselves, but are through user input via website registration pages, payments pages, and other online forms. To ensure proper security measures are in place this information should be encoded through limited interaction via SSL (secure socket layer) certified pages.
Tracking User Behavior
For systems that use third party ad serving networks, such as Google’s AdSense / AdWord pose additional privacy concerns. When leveraging ad serving platforms there is an impact to user privacy being there is no obvious consent given for such tracking. With the rapid evolution around cookie based ad services and tracking user behavior, it brings up the privacy concern of using default standards for cookies.
Opt Out Cookies
Under an opt out scheme, consumers are notified via an alert or window when they load a website. The user must consent to the notice before they can navigate the site and any cookies are planted. At a minimum, the notice is to contain the following: disclosure of information gathering practices, the uses for this information, and policies for processing and disposing of this data.
Opt-out cookies are essentially cookies used to avoid cookies. When a website creates an opt-out cookie in your browser folder, it enables you to block that same website from installing future cookies.With this, Opt Out cookies offer safeguards for user information, and help secure systems against potential security concerns regarding “hidden” cookies
Opt In Cookies
Opt-in is the process that describes an affirmative action user takes to offer their consent for companies to use their data. Unticked checkboxes or buttons are the most common way in which you can implement opt-in mechanisms to obtain users’ consent.
Which One To Use?
If you want to be legally compliant, it is safer to have both the options with opt-out as the default.
Resources
<- Previous Module: Elixir Security || Next Module: Security Anti-Patterns ->