Skip to content

Commit 1f4714c

Browse files
committed
Change default X-XSS-Protection header to '0'
This header has been deprecated and the XSS auditor it triggered has been removed from all major modern browsers (in favour of Content Security Policy) that implemented this header to begin with (Firefox never did). [OWASP](https://owasp.org/www-project-secure-headers/#x-xss-protection) suggests setting this header to '0' to disable the default behaviour on old browsers as it can introduce additional security issues. Added the new behaviour as a framework default from Rails 7.0.
1 parent 5462fbd commit 1f4714c

File tree

8 files changed

+50
-7
lines changed

8 files changed

+50
-7
lines changed

actionpack/test/controller/base_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def test_response_has_default_headers
133133
ActionDispatch::Response.default_headers = {
134134
"X-Frame-Options" => "DENY",
135135
"X-Content-Type-Options" => "nosniff",
136-
"X-XSS-Protection" => "1;"
136+
"X-XSS-Protection" => "0"
137137
}
138138

139139
response_headers = SimpleController.action("hello").call(

actionpack/test/controller/metal_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test_response_does_not_have_default_headers
1515
ActionDispatch::Response.default_headers = {
1616
"X-Frame-Options" => "DENY",
1717
"X-Content-Type-Options" => "nosniff",
18-
"X-XSS-Protection" => "1;"
18+
"X-XSS-Protection" => "0"
1919
}
2020

2121
response_headers = SimpleController.action("hello").call(

actionpack/test/dispatch/response_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def test_only_set_charset_still_defaults_to_text_html
339339
ActionDispatch::Response.default_headers = {
340340
"X-Frame-Options" => "DENY",
341341
"X-Content-Type-Options" => "nosniff",
342-
"X-XSS-Protection" => "1;",
342+
"X-XSS-Protection" => "0",
343343
"X-Download-Options" => "noopen",
344344
"X-Permitted-Cross-Domain-Policies" => "none",
345345
"Referrer-Policy" => "strict-origin-when-cross-origin"
@@ -351,7 +351,7 @@ def test_only_set_charset_still_defaults_to_text_html
351351

352352
assert_equal("DENY", resp.headers["X-Frame-Options"])
353353
assert_equal("nosniff", resp.headers["X-Content-Type-Options"])
354-
assert_equal("1;", resp.headers["X-XSS-Protection"])
354+
assert_equal("0", resp.headers["X-XSS-Protection"])
355355
assert_equal("noopen", resp.headers["X-Download-Options"])
356356
assert_equal("none", resp.headers["X-Permitted-Cross-Domain-Policies"])
357357
assert_equal("strict-origin-when-cross-origin", resp.headers["Referrer-Policy"])

guides/source/configuring.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,7 @@ Is a hash with HTTP headers that are set by default in each response. By default
898898
```ruby
899899
config.action_dispatch.default_headers = {
900900
'X-Frame-Options' => 'SAMEORIGIN',
901-
'X-XSS-Protection' => '1; mode=block',
901+
'X-XSS-Protection' => '0',
902902
'X-Content-Type-Options' => 'nosniff',
903903
'X-Download-Options' => 'noopen',
904904
'X-Permitted-Cross-Domain-Policies' => 'none',
@@ -1681,6 +1681,16 @@ Accepts a string for the HTML tag used to wrap attachments. Defaults to `"action
16811681
- `config.active_storage.video_preview_arguments`: `"-vf 'select=eq(n\\,0)+eq(key\\,1)+gt(scene\\,0.015),loop=loop=-1:size=2,trim=start_frame=1' -frames:v 1 -f image2"`
16821682
- `config.active_record.verify_foreign_keys_for_fixtures`: `true`
16831683
- `config.active_storage.variant_processor`: `:vips`
1684+
- `config.action_dispatch.default_headers`:
1685+
1686+
{
1687+
"X-Frame-Options" => "SAMEORIGIN",
1688+
"X-XSS-Protection" => "0",
1689+
"X-Content-Type-Options" => "nosniff",
1690+
"X-Download-Options" => "noopen",
1691+
"X-Permitted-Cross-Domain-Policies" => "none",
1692+
"Referrer-Policy" => "strict-origin-when-cross-origin"
1693+
}
16841694

16851695
#### For '6.1', defaults from previous versions below and:
16861696

guides/source/security.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,7 @@ Every HTTP response from your Rails application receives the following default s
10241024
```ruby
10251025
config.action_dispatch.default_headers = {
10261026
'X-Frame-Options' => 'SAMEORIGIN',
1027-
'X-XSS-Protection' => '1; mode=block',
1027+
'X-XSS-Protection' => '0',
10281028
'X-Content-Type-Options' => 'nosniff',
10291029
'X-Download-Options' => 'noopen',
10301030
'X-Permitted-Cross-Domain-Policies' => 'none',
@@ -1050,7 +1050,7 @@ config.action_dispatch.default_headers.clear
10501050
Here is a list of common headers:
10511051

10521052
* **X-Frame-Options:** _`SAMEORIGIN` in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or remove this header completely if you want to allow framing on all websites.
1053-
* **X-XSS-Protection:** _`1; mode=block` in Rails by default_ - use XSS Auditor and block page if XSS attack is detected. Set it to '0;' if you want to switch XSS Auditor off(useful if response contents scripts from request parameters)
1053+
* **X-XSS-Protection:** _`0` in Rails by default_ - [deprecated legacy header](https://owasp.org/www-project-secure-headers/#x-xss-protection), set to '0' to disable problematic legacy XSS auditors.
10541054
* **X-Content-Type-Options:** _`nosniff` in Rails by default_ - stops the browser from guessing the MIME type of a file.
10551055
* **X-Content-Security-Policy:** [A powerful mechanism for controlling which sites certain content types can be loaded from](https://w3c.github.io/webappsec-csp/)
10561056
* **Access-Control-Allow-Origin:** Used to control which sites are allowed to bypass same origin policies and send cross-origin requests.

railties/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
* Change default `X-XSS-Protection` header to disable XSS auditor
2+
3+
This header has been deprecated and the XSS auditor it triggered
4+
has been removed from all major modern browsers (in favour of
5+
Content Security Policy) that implemented this header to begin with
6+
(Firefox never did).
7+
8+
[OWASP](https://owasp.org/www-project-secure-headers/#x-xss-protection)
9+
suggests setting this header to '0' to disable the default behaviour
10+
on old browsers as it can introduce additional security issues.
11+
12+
Added the new behaviour as a framework default from Rails 7.0.
13+
14+
*Christian Sutter*
15+
116
* New applications get a dependency on the new `debug` gem, replacing `byebug`.
217

318
*Xavier Noria*

railties/lib/rails/application/configuration.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ def load_defaults(target_version)
198198
load_defaults "6.1"
199199

200200
if respond_to?(:action_dispatch)
201+
action_dispatch.default_headers = {
202+
"X-Frame-Options" => "SAMEORIGIN",
203+
"X-XSS-Protection" => "0",
204+
"X-Content-Type-Options" => "nosniff",
205+
"X-Download-Options" => "noopen",
206+
"X-Permitted-Cross-Domain-Policies" => "none",
207+
"Referrer-Policy" => "strict-origin-when-cross-origin"
208+
}
201209
action_dispatch.return_only_request_media_type_on_content_type = false
202210
end
203211

railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,13 @@
7070
# operations. See the upgrading guide for detail on the changes required.
7171
# The `:mini_magick` option is not deprecated; it's fine to keep using it.
7272
# Rails.application.config.active_storage.variant_processor = :vips
73+
74+
# Change the default headers to disable browsers' flawed legacy XSS protection
75+
# Rails.application.config.action_dispatch.default_headers = {
76+
# "X-Frame-Options" => "SAMEORIGIN",
77+
# "X-XSS-Protection" => "0",
78+
# "X-Content-Type-Options" => "nosniff",
79+
# "X-Download-Options" => "noopen",
80+
# "X-Permitted-Cross-Domain-Policies" => "none",
81+
# "Referrer-Policy" => "strict-origin-when-cross-origin"
82+
# }

0 commit comments

Comments
 (0)