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.