Skip to main content

Insecurely generated cookies - SameSite

Need

Secure generation of cookies with proper SameSite attribute

Context

  • Usage of Ruby for developing web applications and scripting
  • Usage of ActionController::Base for handling controller actions in Ruby on Rails
  • Usage of cookies for managing HTTP cookies in a Node.js application

Description

Non compliant code

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
before_action :set_cookie

private

def set_cookie
cookies[:user_preferences] = {
value: 'dark_mode=true',
expires: 1.year.from_now
}
end
end

In the above code snippet, a cookie named user_preferences is being set in the ApplicationController of a Ruby on Rails application. The ApplicationController is the parent controller from which all other controllers in the application inherit. This means that the set_cookie method will be run before every action in the application, ensuring that the user_preferences cookie is always set.

The set_cookie method sets the user_preferences cookie with a value of 'dark_mode=true' and an expiry date of 1 year from now. However, you'll notice that the SameSite attribute is not being set when the cookie is created.

The SameSite attribute is an effective countermeasure to cross-site request forgery, cross-site script inclusion, and timing attacks. The attribute can have one of three values: Strict, Lax, or None. If the SameSite attribute is not set, it defaults to None, which does not provide any protection against the aforementioned attacks.

This lack of the SameSite attribute in the cookie settings represents a security vulnerability, as it leaves the application exposed to potential attacks.

Steps

  • Update the Ruby on Rails framework to a version that supports the SameSite attribute for cookies.
  • Set the SameSite attribute for the cookies to 'Strict' or 'Lax' to prevent cross-site request forgery (CSRF) attacks.
  • Ensure that the SameSite attribute is set for all cookies generated by the application, not just the 'user_preferences' cookie.
  • Consider using the 'secure' attribute for cookies to ensure they are only sent over HTTPS connections.
  • Test the application thoroughly to ensure that the changes do not introduce any regressions or compatibility issues.

Compliant code

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
before_action :set_cookie

private

def set_cookie
cookies[:user_preferences] = {
value: 'dark_mode=true',
expires: 1.year.from_now,
same_site: :strict, # or :lax
secure: Rails.env.production? # only send cookie over https if in production environment
}
end
end

The updated code now sets the SameSite attribute for the user_preferences cookie to :strict. This means that the cookie will only be sent in a first-party context and not be sent along with requests initiated by third party websites. This can help to mitigate the risk of cross-site request forgery (CSRF) attacks.

The SameSite attribute can also be set to :lax, which is a little less strict. In this mode, the cookie will be sent with top-level navigations and will be sent with GET requests initiated by third party websites.

In addition to setting the SameSite attribute, the secure attribute is also set for the cookie. This attribute ensures that the cookie is only sent over secure (HTTPS) connections. In the updated code, the secure attribute is only set if the application is running in the production environment. This is because HTTPS is typically only used in production and not in development or test environments.

After making these changes, it's important to thoroughly test the application to ensure that the changes do not introduce any regressions or compatibility issues.

References