Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
afc2b424
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
afc2b424
编写于
11月 27, 2017
作者:
A
Andrew White
提交者:
GitHub
11月 27, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #31162 from rails/add-csp-config
Add DSL for configuring Content-Security-Policy header
上级
7ce8a6af
456c3ffd
变更
13
显示空白变更内容
内联
并排
Showing
13 changed file
with
886 addition
and
34 deletion
+886
-34
actionpack/lib/action_controller.rb
actionpack/lib/action_controller.rb
+1
-0
actionpack/lib/action_controller/base.rb
actionpack/lib/action_controller/base.rb
+1
-0
actionpack/lib/action_controller/metal/content_security_policy.rb
...ck/lib/action_controller/metal/content_security_policy.rb
+26
-0
actionpack/lib/action_dispatch.rb
actionpack/lib/action_dispatch.rb
+1
-0
actionpack/lib/action_dispatch/http/content_security_policy.rb
...npack/lib/action_dispatch/http/content_security_policy.rb
+233
-0
actionpack/lib/action_dispatch/http/request.rb
actionpack/lib/action_dispatch/http/request.rb
+1
-0
actionpack/test/dispatch/content_security_policy_test.rb
actionpack/test/dispatch/content_security_policy_test.rb
+359
-0
railties/lib/rails/application.rb
railties/lib/rails/application.rb
+3
-1
railties/lib/rails/application/configuration.rb
railties/lib/rails/application/configuration.rb
+39
-33
railties/lib/rails/application/default_middleware_stack.rb
railties/lib/rails/application/default_middleware_stack.rb
+4
-0
railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt
...mplates/config/initializers/content_security_policy.rb.tt
+20
-0
railties/test/application/content_security_policy_test.rb
railties/test/application/content_security_policy_test.rb
+197
-0
railties/test/application/middleware_test.rb
railties/test/application/middleware_test.rb
+1
-0
未找到文件。
actionpack/lib/action_controller.rb
浏览文件 @
afc2b424
...
@@ -22,6 +22,7 @@ module ActionController
...
@@ -22,6 +22,7 @@ module ActionController
autoload_under
"metal"
do
autoload_under
"metal"
do
autoload
:ConditionalGet
autoload
:ConditionalGet
autoload
:ContentSecurityPolicy
autoload
:Cookies
autoload
:Cookies
autoload
:DataStreaming
autoload
:DataStreaming
autoload
:EtagWithTemplateDigest
autoload
:EtagWithTemplateDigest
...
...
actionpack/lib/action_controller/base.rb
浏览文件 @
afc2b424
...
@@ -225,6 +225,7 @@ def self.without_modules(*modules)
...
@@ -225,6 +225,7 @@ def self.without_modules(*modules)
Flash
,
Flash
,
FormBuilder
,
FormBuilder
,
RequestForgeryProtection
,
RequestForgeryProtection
,
ContentSecurityPolicy
,
ForceSSL
,
ForceSSL
,
Streaming
,
Streaming
,
DataStreaming
,
DataStreaming
,
...
...
actionpack/lib/action_controller/metal/content_security_policy.rb
0 → 100644
浏览文件 @
afc2b424
# frozen_string_literal: true
module
ActionController
#:nodoc:
module
ContentSecurityPolicy
# TODO: Documentation
extend
ActiveSupport
::
Concern
module
ClassMethods
def
content_security_policy
(
**
options
,
&
block
)
before_action
(
options
)
do
if
block_given?
policy
=
request
.
content_security_policy
.
clone
yield
policy
request
.
content_security_policy
=
policy
end
end
end
def
content_security_policy_report_only
(
report_only
=
true
,
**
options
)
before_action
(
options
)
do
request
.
content_security_policy_report_only
=
report_only
end
end
end
end
end
actionpack/lib/action_dispatch.rb
浏览文件 @
afc2b424
...
@@ -42,6 +42,7 @@ class IllegalStateError < StandardError
...
@@ -42,6 +42,7 @@ class IllegalStateError < StandardError
eager_autoload
do
eager_autoload
do
autoload_under
"http"
do
autoload_under
"http"
do
autoload
:ContentSecurityPolicy
autoload
:Request
autoload
:Request
autoload
:Response
autoload
:Response
end
end
...
...
actionpack/lib/action_dispatch/http/content_security_policy.rb
0 → 100644
浏览文件 @
afc2b424
# frozen_string_literal: true
module
ActionDispatch
#:nodoc:
class
ContentSecurityPolicy
class
Middleware
CONTENT_TYPE
=
"Content-Type"
.
freeze
POLICY
=
"Content-Security-Policy"
.
freeze
POLICY_REPORT_ONLY
=
"Content-Security-Policy-Report-Only"
.
freeze
def
initialize
(
app
)
@app
=
app
end
def
call
(
env
)
request
=
ActionDispatch
::
Request
.
new
env
_
,
headers
,
_
=
response
=
@app
.
call
(
env
)
return
response
unless
html_response?
(
headers
)
return
response
if
policy_present?
(
headers
)
if
policy
=
request
.
content_security_policy
headers
[
header_name
(
request
)]
=
policy
.
build
(
request
.
controller_instance
)
end
response
end
private
def
html_response?
(
headers
)
if
content_type
=
headers
[
CONTENT_TYPE
]
content_type
=~
/html/
end
end
def
header_name
(
request
)
if
request
.
content_security_policy_report_only
POLICY_REPORT_ONLY
else
POLICY
end
end
def
policy_present?
(
headers
)
headers
[
POLICY
]
||
headers
[
POLICY_REPORT_ONLY
]
end
end
module
Request
POLICY
=
"action_dispatch.content_security_policy"
.
freeze
POLICY_REPORT_ONLY
=
"action_dispatch.content_security_policy_report_only"
.
freeze
def
content_security_policy
get_header
(
POLICY
)
end
def
content_security_policy
=
(
policy
)
set_header
(
POLICY
,
policy
)
end
def
content_security_policy_report_only
get_header
(
POLICY_REPORT_ONLY
)
end
def
content_security_policy_report_only
=
(
value
)
set_header
(
POLICY_REPORT_ONLY
,
value
)
end
end
MAPPINGS
=
{
self:
"'self'"
,
unsafe_eval:
"'unsafe-eval'"
,
unsafe_inline:
"'unsafe-inline'"
,
none:
"'none'"
,
http:
"http:"
,
https:
"https:"
,
data:
"data:"
,
mediastream:
"mediastream:"
,
blob:
"blob:"
,
filesystem:
"filesystem:"
,
report_sample:
"'report-sample'"
,
strict_dynamic:
"'strict-dynamic'"
}.
freeze
DIRECTIVES
=
{
base_uri:
"base-uri"
,
child_src:
"child-src"
,
connect_src:
"connect-src"
,
default_src:
"default-src"
,
font_src:
"font-src"
,
form_action:
"form-action"
,
frame_ancestors:
"frame-ancestors"
,
frame_src:
"frame-src"
,
img_src:
"img-src"
,
manifest_src:
"manifest-src"
,
media_src:
"media-src"
,
object_src:
"object-src"
,
script_src:
"script-src"
,
style_src:
"style-src"
,
worker_src:
"worker-src"
}.
freeze
private_constant
:MAPPINGS
,
:DIRECTIVES
attr_reader
:directives
def
initialize
@directives
=
{}
yield
self
if
block_given?
end
def
initialize_copy
(
other
)
@directives
=
copy_directives
(
other
.
directives
)
end
DIRECTIVES
.
each
do
|
name
,
directive
|
define_method
(
name
)
do
|*
sources
|
if
sources
.
first
@directives
[
directive
]
=
apply_mappings
(
sources
)
else
@directives
.
delete
(
directive
)
end
end
end
def
block_all_mixed_content
(
enabled
=
true
)
if
enabled
@directives
[
"block-all-mixed-content"
]
=
true
else
@directives
.
delete
(
"block-all-mixed-content"
)
end
end
def
plugin_types
(
*
types
)
if
types
.
first
@directives
[
"plugin-types"
]
=
types
else
@directives
.
delete
(
"plugin-types"
)
end
end
def
report_uri
(
uri
)
@directives
[
"report-uri"
]
=
[
uri
]
end
def
require_sri_for
(
*
types
)
if
types
.
first
@directives
[
"require-sri-for"
]
=
types
else
@directives
.
delete
(
"require-sri-for"
)
end
end
def
sandbox
(
*
values
)
if
values
.
empty?
@directives
[
"sandbox"
]
=
true
elsif
values
.
first
@directives
[
"sandbox"
]
=
values
else
@directives
.
delete
(
"sandbox"
)
end
end
def
upgrade_insecure_requests
(
enabled
=
true
)
if
enabled
@directives
[
"upgrade-insecure-requests"
]
=
true
else
@directives
.
delete
(
"upgrade-insecure-requests"
)
end
end
def
build
(
context
=
nil
)
build_directives
(
context
).
compact
.
join
(
"; "
)
+
";"
end
private
def
copy_directives
(
directives
)
directives
.
transform_values
{
|
sources
|
sources
.
map
(
&
:dup
)
}
end
def
apply_mappings
(
sources
)
sources
.
map
do
|
source
|
case
source
when
Symbol
apply_mapping
(
source
)
when
String
,
Proc
source
else
raise
ArgumentError
,
"Invalid content security policy source:
#{
source
.
inspect
}
"
end
end
end
def
apply_mapping
(
source
)
MAPPINGS
.
fetch
(
source
)
do
raise
ArgumentError
,
"Unknown content security policy source mapping:
#{
source
.
inspect
}
"
end
end
def
build_directives
(
context
)
@directives
.
map
do
|
directive
,
sources
|
if
sources
.
is_a?
(
Array
)
"
#{
directive
}
#{
build_directive
(
sources
,
context
).
join
(
' '
)
}
"
elsif
sources
directive
else
nil
end
end
end
def
build_directive
(
sources
,
context
)
sources
.
map
{
|
source
|
resolve_source
(
source
,
context
)
}
end
def
resolve_source
(
source
,
context
)
case
source
when
String
source
when
Symbol
source
.
to_s
when
Proc
if
context
.
nil?
raise
RuntimeError
,
"Missing context for the dynamic content security policy source:
#{
source
.
inspect
}
"
else
context
.
instance_exec
(
&
source
)
end
else
raise
RuntimeError
,
"Unexpected content security policy source:
#{
source
.
inspect
}
"
end
end
end
end
actionpack/lib/action_dispatch/http/request.rb
浏览文件 @
afc2b424
...
@@ -22,6 +22,7 @@ class Request
...
@@ -22,6 +22,7 @@ class Request
include
ActionDispatch
::
Http
::
Parameters
include
ActionDispatch
::
Http
::
Parameters
include
ActionDispatch
::
Http
::
FilterParameters
include
ActionDispatch
::
Http
::
FilterParameters
include
ActionDispatch
::
Http
::
URL
include
ActionDispatch
::
Http
::
URL
include
ActionDispatch
::
ContentSecurityPolicy
::
Request
include
Rack
::
Request
::
Env
include
Rack
::
Request
::
Env
autoload
:Session
,
"action_dispatch/request/session"
autoload
:Session
,
"action_dispatch/request/session"
...
...
actionpack/test/dispatch/content_security_policy_test.rb
0 → 100644
浏览文件 @
afc2b424
# frozen_string_literal: true
require
"abstract_unit"
class
ContentSecurityPolicyTest
<
ActiveSupport
::
TestCase
def
setup
@policy
=
ActionDispatch
::
ContentSecurityPolicy
.
new
end
def
test_build
assert_equal
";"
,
@policy
.
build
@policy
.
script_src
:self
assert_equal
"script-src 'self';"
,
@policy
.
build
end
def
test_mappings
@policy
.
script_src
:data
assert_equal
"script-src data:;"
,
@policy
.
build
@policy
.
script_src
:mediastream
assert_equal
"script-src mediastream:;"
,
@policy
.
build
@policy
.
script_src
:blob
assert_equal
"script-src blob:;"
,
@policy
.
build
@policy
.
script_src
:filesystem
assert_equal
"script-src filesystem:;"
,
@policy
.
build
@policy
.
script_src
:self
assert_equal
"script-src 'self';"
,
@policy
.
build
@policy
.
script_src
:unsafe_inline
assert_equal
"script-src 'unsafe-inline';"
,
@policy
.
build
@policy
.
script_src
:unsafe_eval
assert_equal
"script-src 'unsafe-eval';"
,
@policy
.
build
@policy
.
script_src
:none
assert_equal
"script-src 'none';"
,
@policy
.
build
@policy
.
script_src
:strict_dynamic
assert_equal
"script-src 'strict-dynamic';"
,
@policy
.
build
@policy
.
script_src
:none
,
:report_sample
assert_equal
"script-src 'none' 'report-sample';"
,
@policy
.
build
end
def
test_fetch_directives
@policy
.
child_src
:self
assert_match
%r{child-src 'self'}
,
@policy
.
build
@policy
.
child_src
false
assert_no_match
%r{child-src}
,
@policy
.
build
@policy
.
connect_src
:self
assert_match
%r{connect-src 'self'}
,
@policy
.
build
@policy
.
connect_src
false
assert_no_match
%r{connect-src}
,
@policy
.
build
@policy
.
default_src
:self
assert_match
%r{default-src 'self'}
,
@policy
.
build
@policy
.
default_src
false
assert_no_match
%r{default-src}
,
@policy
.
build
@policy
.
font_src
:self
assert_match
%r{font-src 'self'}
,
@policy
.
build
@policy
.
font_src
false
assert_no_match
%r{font-src}
,
@policy
.
build
@policy
.
frame_src
:self
assert_match
%r{frame-src 'self'}
,
@policy
.
build
@policy
.
frame_src
false
assert_no_match
%r{frame-src}
,
@policy
.
build
@policy
.
img_src
:self
assert_match
%r{img-src 'self'}
,
@policy
.
build
@policy
.
img_src
false
assert_no_match
%r{img-src}
,
@policy
.
build
@policy
.
manifest_src
:self
assert_match
%r{manifest-src 'self'}
,
@policy
.
build
@policy
.
manifest_src
false
assert_no_match
%r{manifest-src}
,
@policy
.
build
@policy
.
media_src
:self
assert_match
%r{media-src 'self'}
,
@policy
.
build
@policy
.
media_src
false
assert_no_match
%r{media-src}
,
@policy
.
build
@policy
.
object_src
:self
assert_match
%r{object-src 'self'}
,
@policy
.
build
@policy
.
object_src
false
assert_no_match
%r{object-src}
,
@policy
.
build
@policy
.
script_src
:self
assert_match
%r{script-src 'self'}
,
@policy
.
build
@policy
.
script_src
false
assert_no_match
%r{script-src}
,
@policy
.
build
@policy
.
style_src
:self
assert_match
%r{style-src 'self'}
,
@policy
.
build
@policy
.
style_src
false
assert_no_match
%r{style-src}
,
@policy
.
build
@policy
.
worker_src
:self
assert_match
%r{worker-src 'self'}
,
@policy
.
build
@policy
.
worker_src
false
assert_no_match
%r{worker-src}
,
@policy
.
build
end
def
test_document_directives
@policy
.
base_uri
"https://example.com"
assert_match
%r{base-uri https://example
\.
com;}
,
@policy
.
build
@policy
.
plugin_types
"application/x-shockwave-flash"
assert_match
%r{plugin-types application/x-shockwave-flash;}
,
@policy
.
build
@policy
.
sandbox
assert_match
%r{sandbox;}
,
@policy
.
build
@policy
.
sandbox
"allow-scripts"
,
"allow-modals"
assert_match
%r{sandbox allow-scripts allow-modals;}
,
@policy
.
build
@policy
.
sandbox
false
assert_no_match
%r{sandbox}
,
@policy
.
build
end
def
test_navigation_directives
@policy
.
form_action
:self
assert_match
%r{form-action 'self';}
,
@policy
.
build
@policy
.
frame_ancestors
:self
assert_match
%r{frame-ancestors 'self';}
,
@policy
.
build
end
def
test_reporting_directives
@policy
.
report_uri
"/violations"
assert_match
%r{report-uri /violations;}
,
@policy
.
build
end
def
test_other_directives
@policy
.
block_all_mixed_content
assert_match
%r{block-all-mixed-content;}
,
@policy
.
build
@policy
.
block_all_mixed_content
false
assert_no_match
%r{block-all-mixed-content}
,
@policy
.
build
@policy
.
require_sri_for
:script
,
:style
assert_match
%r{require-sri-for script style;}
,
@policy
.
build
@policy
.
require_sri_for
"script"
,
"style"
assert_match
%r{require-sri-for script style;}
,
@policy
.
build
@policy
.
require_sri_for
assert_no_match
%r{require-sri-for}
,
@policy
.
build
@policy
.
upgrade_insecure_requests
assert_match
%r{upgrade-insecure-requests;}
,
@policy
.
build
@policy
.
upgrade_insecure_requests
false
assert_no_match
%r{upgrade-insecure-requests}
,
@policy
.
build
end
def
test_multiple_sources
@policy
.
script_src
:self
,
:https
assert_equal
"script-src 'self' https:;"
,
@policy
.
build
end
def
test_multiple_directives
@policy
.
script_src
:self
,
:https
@policy
.
style_src
:self
,
:https
assert_equal
"script-src 'self' https:; style-src 'self' https:;"
,
@policy
.
build
end
def
test_dynamic_directives
request
=
Struct
.
new
(
:host
).
new
(
"www.example.com"
)
controller
=
Struct
.
new
(
:request
).
new
(
request
)
@policy
.
script_src
->
{
request
.
host
}
assert_equal
"script-src www.example.com;"
,
@policy
.
build
(
controller
)
end
def
test_mixed_static_and_dynamic_directives
@policy
.
script_src
:self
,
->
{
"foo.com"
},
"bar.com"
assert_equal
"script-src 'self' foo.com bar.com;"
,
@policy
.
build
(
Object
.
new
)
end
def
test_invalid_directive_source
exception
=
assert_raises
(
ArgumentError
)
do
@policy
.
script_src
[
:self
]
end
assert_equal
"Invalid content security policy source: [:self]"
,
exception
.
message
end
def
test_missing_context_for_dynamic_source
@policy
.
script_src
->
{
request
.
host
}
exception
=
assert_raises
(
RuntimeError
)
do
@policy
.
build
end
assert_match
%r{
\A
Missing context for the dynamic content security policy source:}
,
exception
.
message
end
def
test_raises_runtime_error_when_unexpected_source
@policy
.
plugin_types
[
:flash
]
exception
=
assert_raises
(
RuntimeError
)
do
@policy
.
build
end
assert_match
%r{
\A
Unexpected content security policy source:}
,
exception
.
message
end
end
class
ContentSecurityPolicyIntegrationTest
<
ActionDispatch
::
IntegrationTest
class
PolicyController
<
ActionController
::
Base
content_security_policy
only: :inline
do
|
p
|
p
.
default_src
"https://example.com"
end
content_security_policy
only: :conditional
,
if: :condition?
do
|
p
|
p
.
default_src
"https://true.example.com"
end
content_security_policy
only: :conditional
,
unless: :condition?
do
|
p
|
p
.
default_src
"https://false.example.com"
end
content_security_policy
only: :report_only
do
|
p
|
p
.
report_uri
"/violations"
end
content_security_policy_report_only
only: :report_only
def
index
head
:ok
end
def
inline
head
:ok
end
def
conditional
head
:ok
end
def
report_only
head
:ok
end
private
def
condition?
params
[
:condition
]
==
"true"
end
end
ROUTES
=
ActionDispatch
::
Routing
::
RouteSet
.
new
ROUTES
.
draw
do
scope
module:
"content_security_policy_integration_test"
do
get
"/"
,
to:
"policy#index"
get
"/inline"
,
to:
"policy#inline"
get
"/conditional"
,
to:
"policy#conditional"
get
"/report-only"
,
to:
"policy#report_only"
end
end
POLICY
=
ActionDispatch
::
ContentSecurityPolicy
.
new
do
|
p
|
p
.
default_src
:self
end
class
PolicyConfigMiddleware
def
initialize
(
app
)
@app
=
app
end
def
call
(
env
)
env
[
"action_dispatch.content_security_policy"
]
=
POLICY
env
[
"action_dispatch.content_security_policy_report_only"
]
=
false
env
[
"action_dispatch.show_exceptions"
]
=
false
@app
.
call
(
env
)
end
end
APP
=
build_app
(
ROUTES
)
do
|
middleware
|
middleware
.
use
PolicyConfigMiddleware
middleware
.
use
ActionDispatch
::
ContentSecurityPolicy
::
Middleware
end
def
app
APP
end
def
test_generates_content_security_policy_header
get
"/"
assert_policy
"default-src 'self';"
end
def
test_generates_inline_content_security_policy
get
"/inline"
assert_policy
"default-src https://example.com;"
end
def
test_generates_conditional_content_security_policy
get
"/conditional"
,
params:
{
condition:
"true"
}
assert_policy
"default-src https://true.example.com;"
get
"/conditional"
,
params:
{
condition:
"false"
}
assert_policy
"default-src https://false.example.com;"
end
def
test_generates_report_only_content_security_policy
get
"/report-only"
assert_policy
"default-src 'self'; report-uri /violations;"
,
report_only:
true
end
private
def
env_config
Rails
.
application
.
env_config
end
def
content_security_policy
env_config
[
"action_dispatch.content_security_policy"
]
end
def
content_security_policy
=
(
policy
)
env_config
[
"action_dispatch.content_security_policy"
]
=
policy
end
def
assert_policy
(
expected
,
report_only:
false
)
assert_response
:success
if
report_only
expected_header
=
"Content-Security-Policy-Report-Only"
unexpected_header
=
"Content-Security-Policy"
else
expected_header
=
"Content-Security-Policy"
unexpected_header
=
"Content-Security-Policy-Report-Only"
end
assert_nil
response
.
headers
[
unexpected_header
]
assert_equal
expected
,
response
.
headers
[
expected_header
]
end
end
railties/lib/rails/application.rb
浏览文件 @
afc2b424
...
@@ -266,7 +266,9 @@ def env_config
...
@@ -266,7 +266,9 @@ def env_config
"action_dispatch.signed_cookie_digest"
=>
config
.
action_dispatch
.
signed_cookie_digest
,
"action_dispatch.signed_cookie_digest"
=>
config
.
action_dispatch
.
signed_cookie_digest
,
"action_dispatch.cookies_serializer"
=>
config
.
action_dispatch
.
cookies_serializer
,
"action_dispatch.cookies_serializer"
=>
config
.
action_dispatch
.
cookies_serializer
,
"action_dispatch.cookies_digest"
=>
config
.
action_dispatch
.
cookies_digest
,
"action_dispatch.cookies_digest"
=>
config
.
action_dispatch
.
cookies_digest
,
"action_dispatch.cookies_rotations"
=>
config
.
action_dispatch
.
cookies_rotations
"action_dispatch.cookies_rotations"
=>
config
.
action_dispatch
.
cookies_rotations
,
"action_dispatch.content_security_policy"
=>
config
.
content_security_policy
,
"action_dispatch.content_security_policy_report_only"
=>
config
.
content_security_policy_report_only
)
)
end
end
end
end
...
...
railties/lib/rails/application/configuration.rb
浏览文件 @
afc2b424
...
@@ -16,7 +16,7 @@ class Configuration < ::Rails::Engine::Configuration
...
@@ -16,7 +16,7 @@ class Configuration < ::Rails::Engine::Configuration
:ssl_options
,
:public_file_server
,
:ssl_options
,
:public_file_server
,
:session_options
,
:time_zone
,
:reload_classes_only_on_change
,
:session_options
,
:time_zone
,
:reload_classes_only_on_change
,
:beginning_of_week
,
:filter_redirect
,
:x
,
:enable_dependency_loading
,
:beginning_of_week
,
:filter_redirect
,
:x
,
:enable_dependency_loading
,
:read_encrypted_secrets
,
:log_level
:read_encrypted_secrets
,
:log_level
,
:content_security_policy_report_only
attr_reader
:encoding
,
:api_only
attr_reader
:encoding
,
:api_only
...
@@ -54,6 +54,8 @@ def initialize(*)
...
@@ -54,6 +54,8 @@ def initialize(*)
@x
=
Custom
.
new
@x
=
Custom
.
new
@enable_dependency_loading
=
false
@enable_dependency_loading
=
false
@read_encrypted_secrets
=
false
@read_encrypted_secrets
=
false
@content_security_policy
=
nil
@content_security_policy_report_only
=
false
end
end
def
load_defaults
(
target_version
)
def
load_defaults
(
target_version
)
...
@@ -233,6 +235,10 @@ def annotations
...
@@ -233,6 +235,10 @@ def annotations
SourceAnnotationExtractor
::
Annotation
SourceAnnotationExtractor
::
Annotation
end
end
def
content_security_policy
(
&
block
)
@content_security_policy
||=
ActionDispatch
::
ContentSecurityPolicy
.
new
(
&
block
)
end
class
Custom
#:nodoc:
class
Custom
#:nodoc:
def
initialize
def
initialize
@configurations
=
Hash
.
new
@configurations
=
Hash
.
new
...
...
railties/lib/rails/application/default_middleware_stack.rb
浏览文件 @
afc2b424
...
@@ -63,6 +63,10 @@ def build_stack
...
@@ -63,6 +63,10 @@ def build_stack
middleware
.
use
::
ActionDispatch
::
Flash
middleware
.
use
::
ActionDispatch
::
Flash
end
end
unless
config
.
api_only
middleware
.
use
::
ActionDispatch
::
ContentSecurityPolicy
::
Middleware
end
middleware
.
use
::
Rack
::
Head
middleware
.
use
::
Rack
::
Head
middleware
.
use
::
Rack
::
ConditionalGet
middleware
.
use
::
Rack
::
ConditionalGet
middleware
.
use
::
Rack
::
ETag
,
"no-cache"
middleware
.
use
::
Rack
::
ETag
,
"no-cache"
...
...
railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt
0 → 100644
浏览文件 @
afc2b424
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
p.font_src :self, :https, :data
p.img_src :self, :https, :data
p.object_src :none
p.script_src :self, :https
p.style_src :self, :https, :unsafe_inline
# Specify URI for violation reports
# p.report_uri "/csp-violation-report-endpoint"
end
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true
railties/test/application/content_security_policy_test.rb
0 → 100644
浏览文件 @
afc2b424
# frozen_string_literal: true
require
"isolation/abstract_unit"
require
"rack/test"
module
ApplicationTests
class
ContentSecurityPolicyTest
<
ActiveSupport
::
TestCase
include
ActiveSupport
::
Testing
::
Isolation
include
Rack
::
Test
::
Methods
def
setup
build_app
end
def
teardown
teardown_app
end
test
"default content security policy is empty"
do
controller
:pages
,
<<-
RUBY
class PagesController < ApplicationController
def index
render html: "<h1>Welcome to Rails!</h1>"
end
end
RUBY
app_file
"config/routes.rb"
,
<<-
RUBY
Rails.application.routes.draw do
root to: "pages#index"
end
RUBY
app
(
"development"
)
get
"/"
assert_equal
";"
,
last_response
.
headers
[
"Content-Security-Policy"
]
end
test
"global content security policy in an initializer"
do
controller
:pages
,
<<-
RUBY
class PagesController < ApplicationController
def index
render html: "<h1>Welcome to Rails!</h1>"
end
end
RUBY
app_file
"config/initializers/content_security_policy.rb"
,
<<-
RUBY
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
end
RUBY
app_file
"config/routes.rb"
,
<<-
RUBY
Rails.application.routes.draw do
root to: "pages#index"
end
RUBY
app
(
"development"
)
get
"/"
assert_policy
"default-src 'self' https:;"
end
test
"global report only content security policy in an initializer"
do
controller
:pages
,
<<-
RUBY
class PagesController < ApplicationController
def index
render html: "<h1>Welcome to Rails!</h1>"
end
end
RUBY
app_file
"config/initializers/content_security_policy.rb"
,
<<-
RUBY
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
end
Rails.application.config.content_security_policy_report_only = true
RUBY
app_file
"config/routes.rb"
,
<<-
RUBY
Rails.application.routes.draw do
root to: "pages#index"
end
RUBY
app
(
"development"
)
get
"/"
assert_policy
"default-src 'self' https:;"
,
report_only:
true
end
test
"override content security policy in a controller"
do
controller
:pages
,
<<-
RUBY
class PagesController < ApplicationController
content_security_policy do |p|
p.default_src "https://example.com"
end
def index
render html: "<h1>Welcome to Rails!</h1>"
end
end
RUBY
app_file
"config/initializers/content_security_policy.rb"
,
<<-
RUBY
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
end
RUBY
app_file
"config/routes.rb"
,
<<-
RUBY
Rails.application.routes.draw do
root to: "pages#index"
end
RUBY
app
(
"development"
)
get
"/"
assert_policy
"default-src https://example.com;"
end
test
"override content security policy to report only in a controller"
do
controller
:pages
,
<<-
RUBY
class PagesController < ApplicationController
content_security_policy_report_only
def index
render html: "<h1>Welcome to Rails!</h1>"
end
end
RUBY
app_file
"config/initializers/content_security_policy.rb"
,
<<-
RUBY
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
end
RUBY
app_file
"config/routes.rb"
,
<<-
RUBY
Rails.application.routes.draw do
root to: "pages#index"
end
RUBY
app
(
"development"
)
get
"/"
assert_policy
"default-src 'self' https:;"
,
report_only:
true
end
test
"global content security policy added to rack app"
do
app_file
"config/initializers/content_security_policy.rb"
,
<<-
RUBY
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
end
RUBY
app_file
"config/routes.rb"
,
<<-
RUBY
Rails.application.routes.draw do
app = ->(env) {
[200, { "Content-Type" => "text/html" }, ["<p>Hello, World!</p>"]]
}
root to: app
end
RUBY
app
(
"development"
)
get
"/"
assert_policy
"default-src 'self' https:;"
end
private
def
assert_policy
(
expected
,
report_only:
false
)
assert_equal
200
,
last_response
.
status
if
report_only
expected_header
=
"Content-Security-Policy-Report-Only"
unexpected_header
=
"Content-Security-Policy"
else
expected_header
=
"Content-Security-Policy"
unexpected_header
=
"Content-Security-Policy-Report-Only"
end
assert_nil
last_response
.
headers
[
unexpected_header
]
assert_equal
expected
,
last_response
.
headers
[
expected_header
]
end
end
end
railties/test/application/middleware_test.rb
浏览文件 @
afc2b424
...
@@ -42,6 +42,7 @@ def app
...
@@ -42,6 +42,7 @@ def app
"ActionDispatch::Cookies"
,
"ActionDispatch::Cookies"
,
"ActionDispatch::Session::CookieStore"
,
"ActionDispatch::Session::CookieStore"
,
"ActionDispatch::Flash"
,
"ActionDispatch::Flash"
,
"ActionDispatch::ContentSecurityPolicy::Middleware"
,
"Rack::Head"
,
"Rack::Head"
,
"Rack::ConditionalGet"
,
"Rack::ConditionalGet"
,
"Rack::ETag"
"Rack::ETag"
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录