Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
35970cbf
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,发现更多精彩内容 >>
未验证
提交
35970cbf
编写于
4月 18, 2018
作者:
A
Andrew White
提交者:
Andrey Novikov
4月 18, 2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Pass nonce to CSP policy from outside
上级
b9b66072
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
97 addition
and
53 deletion
+97
-53
actionpack/CHANGELOG.md
actionpack/CHANGELOG.md
+1
-1
actionpack/lib/action_dispatch/http/content_security_policy.rb
...npack/lib/action_dispatch/http/content_security_policy.rb
+24
-31
actionpack/test/dispatch/content_security_policy_test.rb
actionpack/test/dispatch/content_security_policy_test.rb
+72
-21
未找到文件。
actionpack/CHANGELOG.md
浏览文件 @
35970cbf
...
...
@@ -2,7 +2,7 @@
Fixes [#35297](https://github.com/rails/rails/issues/32597).
*Andrey Novikov*
*Andrey Novikov*
, *Andrew White*
*
Move default headers configuration into their own module that can be included in controllers.
...
...
actionpack/lib/action_dispatch/http/content_security_policy.rb
浏览文件 @
35970cbf
...
...
@@ -21,7 +21,8 @@ def call(env)
return
response
if
policy_present?
(
headers
)
if
policy
=
request
.
content_security_policy
headers
[
header_name
(
request
)]
=
policy
.
build
(
request
)
nonce
=
request
.
content_security_policy_nonce
headers
[
header_name
(
request
)]
=
policy
.
build
(
request
.
controller_instance
,
nonce
)
end
response
...
...
@@ -95,14 +96,6 @@ def generate_content_security_policy_nonce
end
end
class
NonceGenerator
def
call
(
request
)
if
nonce
=
request
&
.
content_security_policy_nonce
"'nonce-
#{
nonce
}
'"
end
end
end
MAPPINGS
=
{
self:
"'self'"
,
unsafe_eval:
"'unsafe-eval'"
,
...
...
@@ -133,12 +126,14 @@ def call(request)
manifest_src:
"manifest-src"
,
media_src:
"media-src"
,
object_src:
"object-src"
,
# script_src handled differently
script_src:
"script-src"
,
style_src:
"style-src"
,
worker_src:
"worker-src"
}.
freeze
private_constant
:MAPPINGS
,
:DIRECTIVES
NONCE_DIRECTIVES
=
%w[script-src]
.
freeze
private_constant
:MAPPINGS
,
:DIRECTIVES
,
:NONCE_DIRECTIVES
attr_reader
:directives
...
...
@@ -161,15 +156,6 @@ def initialize_copy(other)
end
end
def
script_src
(
*
sources
)
if
sources
.
first
@directives
[
"script-src"
]
=
apply_mappings
(
sources
)
@directives
[
"script-src"
]
<<
NonceGenerator
.
new
else
@directives
.
delete
(
"script-src"
)
end
end
def
block_all_mixed_content
(
enabled
=
true
)
if
enabled
@directives
[
"block-all-mixed-content"
]
=
true
...
...
@@ -216,8 +202,8 @@ def upgrade_insecure_requests(enabled = true)
end
end
def
build
(
request
=
nil
)
build_directives
(
request
).
compact
.
join
(
"; "
)
def
build
(
context
=
nil
,
nonce
=
nil
)
build_directives
(
context
,
nonce
).
compact
.
join
(
"; "
)
end
private
...
...
@@ -240,10 +226,15 @@ def apply_mapping(source)
end
end
def
build_directives
(
request
)
def
build_directives
(
context
,
nonce
)
@directives
.
map
do
|
directive
,
sources
|
if
sources
.
is_a?
(
Array
)
"
#{
directive
}
#{
build_directive
(
sources
,
request
).
compact
.
join
(
' '
)
}
"
"
#{
directive
}
#{
build_directive
(
sources
,
context
).
join
(
' '
)
}
"
if
nonce
&&
nonce_directive?
(
directive
)
"
#{
directive
}
#{
build_directive
(
sources
,
context
).
join
(
' '
)
}
'nonce-
#{
nonce
}
'"
else
"
#{
directive
}
#{
build_directive
(
sources
,
context
).
join
(
' '
)
}
"
end
elsif
sources
directive
else
...
...
@@ -252,27 +243,29 @@ def build_directives(request)
end
end
def
build_directive
(
sources
,
reques
t
)
sources
.
map
{
|
source
|
resolve_source
(
source
,
reques
t
)
}
def
build_directive
(
sources
,
contex
t
)
sources
.
map
{
|
source
|
resolve_source
(
source
,
contex
t
)
}
end
def
resolve_source
(
source
,
reques
t
)
def
resolve_source
(
source
,
contex
t
)
case
source
when
String
source
when
Symbol
source
.
to_s
when
Proc
if
request
&
.
controller_instance
.
nil?
if
context
.
nil?
raise
RuntimeError
,
"Missing context for the dynamic content security policy source:
#{
source
.
inspect
}
"
else
request
.
controller_instance
.
instance_exec
(
&
source
)
context
.
instance_exec
(
&
source
)
end
when
NonceGenerator
source
.
call
(
request
)
else
raise
RuntimeError
,
"Unexpected content security policy source:
#{
source
.
inspect
}
"
end
end
def
nonce_directive?
(
directive
)
NONCE_DIRECTIVES
.
include?
(
directive
)
end
end
end
actionpack/test/dispatch/content_security_policy_test.rb
浏览文件 @
35970cbf
...
...
@@ -201,17 +201,17 @@ def test_multiple_directives
def
test_dynamic_directives
request
=
ActionDispatch
::
Request
.
new
(
"HTTP_HOST"
=>
"www.example.com"
)
request
.
controller_instance
=
Struct
.
new
(
:request
).
new
(
request
)
controller
=
Struct
.
new
(
:request
).
new
(
request
)
@policy
.
script_src
->
{
request
.
host
}
assert_equal
"script-src www.example.com"
,
@policy
.
build
(
request
)
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"
request
=
ActionDispatch
::
Request
.
new
({})
request
.
controller_instance
=
Struct
.
new
(
:request
).
new
(
request
)
assert_equal
"script-src 'self' foo.com bar.com"
,
@policy
.
build
(
request
)
controller
=
Struct
.
new
(
:request
).
new
(
request
)
assert_equal
"script-src 'self' foo.com bar.com"
,
@policy
.
build
(
controller
)
end
def
test_invalid_directive_source
...
...
@@ -243,25 +243,88 @@ def test_raises_runtime_error_when_unexpected_source
end
end
class
DefaultContentSecurityPolicyIntegrationTest
<
ActionDispatch
::
IntegrationTest
class
PolicyController
<
ActionController
::
Base
def
index
head
:ok
end
end
ROUTES
=
ActionDispatch
::
Routing
::
RouteSet
.
new
ROUTES
.
draw
do
scope
module:
"default_content_security_policy_integration_test"
do
get
"/"
,
to:
"policy#index"
end
end
POLICY
=
ActionDispatch
::
ContentSecurityPolicy
.
new
do
|
p
|
p
.
default_src
:self
p
.
script_src
:https
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_nonce_generator"
]
=
proc
{
"iyhD0Yc0W+c="
}
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_adds_nonce_to_script_src_content_security_policy_only_once
get
"/"
get
"/"
assert_policy
"default-src 'self'; script-src https: 'nonce-iyhD0Yc0W+c='"
end
private
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
class
ContentSecurityPolicyIntegrationTest
<
ActionDispatch
::
IntegrationTest
class
PolicyController
<
ActionController
::
Base
content_security_policy
only: :inline
do
|
p
|
p
.
default_src
"https://example.com"
p
.
script_src
false
end
content_security_policy
only: :conditional
,
if: :condition?
do
|
p
|
p
.
default_src
"https://true.example.com"
p
.
script_src
false
end
content_security_policy
only: :conditional
,
unless: :condition?
do
|
p
|
p
.
default_src
"https://false.example.com"
p
.
script_src
false
end
content_security_policy
only: :report_only
do
|
p
|
p
.
script_src
false
p
.
report_uri
"/violations"
end
...
...
@@ -298,10 +361,6 @@ def no_policy
head
:ok
end
def
default_script_src
head
:ok
end
private
def
condition?
params
[
:condition
]
==
"true"
...
...
@@ -317,13 +376,11 @@ def condition?
get
"/report-only"
,
to:
"policy#report_only"
get
"/script-src"
,
to:
"policy#script_src"
get
"/no-policy"
,
to:
"policy#no_policy"
get
"/default-script-src"
,
to:
"policy#default_script_src"
end
end
POLICY
=
ActionDispatch
::
ContentSecurityPolicy
.
new
do
|
p
|
p
.
default_src
:self
p
.
script_src
:https
end
class
PolicyConfigMiddleware
...
...
@@ -352,7 +409,7 @@ def app
def
test_generates_content_security_policy_header
get
"/"
assert_policy
"default-src 'self'
; script-src https: 'nonce-iyhD0Yc0W+c='
"
assert_policy
"default-src 'self'"
end
def
test_generates_inline_content_security_policy
...
...
@@ -378,12 +435,6 @@ def test_adds_nonce_to_script_src_content_security_policy
assert_policy
"script-src 'self' 'nonce-iyhD0Yc0W+c='"
end
def
test_adds_nonce_to_script_src_content_security_policy_only_once
get
"/default-script-src"
get
"/default-script-src"
assert_policy
"default-src 'self'; script-src https: 'nonce-iyhD0Yc0W+c='"
end
def
test_generates_no_content_security_policy
get
"/no-policy"
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录