Insecure or unset HTTP headers - Strict Transport Security
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
Non compliant code
# 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.
Compliant code
# 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.