Insecure or unset HTTP headers - Strict Transport Security - Ruby
Need
Enforcement of Strict Transport Security (HSTS) headers
Context
- Usage of Ruby 2.0+ for Ruby programming language version compatibility
- Usage of Ruby for building dynamic and object-oriented applications
- Usage of Rails framework for building web applications
Description
Insecure Code Example
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_headers
private
def set_headers
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
response.headers['X-XSS-Protection'] = '1; mode=block'
response.headers['X-Content-Type-Options'] = 'nosniff'
# Missing Strict-Transport-Security header
end
end
This code is from a Ruby on Rails application, specifically the `ApplicationController` which is the main controller from which all other controllers in the application inherit. The `before_action :set_headers` line ensures that the `set_headers` method is called before every action in every controller. The `set_headers` method itself is setting several important HTTP security headers. `X-Frame-Options` is set to 'SAMEORIGIN' to prevent clickjacking attacks, by ensuring that the content can only be framed by pages on the same domain. `X-XSS-Protection` is set to '1; mode=block' to enable XSS filtering. If a cross-site scripting attack is detected, rather than sanitizing the page, the browser will prevent rendering of the page. `X-Content-Type-Options` is set to 'nosniff' to prevent the browser from MIME-sniffing a response away from the declared content-type. However, the `Strict-Transport-Security` header is missing. This header is used to enforce secure (HTTP over SSL/TLS) connections to the server. This makes it more difficult for hackers to downgrade the connection to a less secure version. Without this header, even if your site supports HTTPS, a user could potentially end up communicating over an insecure HTTP connection.
Steps
- Add the Strict-Transport-Security header to the response headers.
- Set the value of the Strict-Transport-Security header to include the 'max-age' directive with a sufficiently long duration.
- Ensure that the Strict-Transport-Security header is only sent over HTTPS connections.
- Consider including the 'includeSubDomains' directive in the Strict-Transport-Security header if applicable.
Secure Code Example
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_headers
private
def set_headers
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
response.headers['X-XSS-Protection'] = '1; mode=block'
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains' # Added Strict-Transport-Security header
end
end
The updated code includes the `Strict-Transport-Security` HTTP header in the response headers. This header is a security feature that helps protect the website against man-in-the-middle attacks by enforcing the use of HTTPS. The value of the `Strict-Transport-Security` header has been set to `'max-age=31536000; includeSubDomains'`. This means that the browser should remember for 31536000 seconds (approximately one year) that this site should only be accessed using HTTPS. The `includeSubDomains` directive indicates that this rule applies to all subdomains as well. Please note that the `Strict-Transport-Security` header should only be sent over HTTPS connections. If your application also serves HTTP connections, you should add a condition to only add this header for HTTPS requests. This change helps to mitigate the risk of insecure or unset HTTP headers, enhancing the overall security of the application.
References
Last updated
2023/09/18