Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
79d50ce3
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,体验更适合开发者的 AI 搜索 >>
提交
79d50ce3
编写于
8月 19, 2014
作者:
J
Jeremy Kemper
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #16570 from bradleybuda/breach-mitigation-mask-csrf-token
CSRF token mask from breach-mitigation-rails gem
上级
e40872ff
69fc0e1b
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
71 addition
and
8 deletion
+71
-8
actionpack/lib/action_controller/metal/request_forgery_protection.rb
...lib/action_controller/metal/request_forgery_protection.rb
+65
-3
actionpack/test/controller/request_forgery_protection_test.rb
...onpack/test/controller/request_forgery_protection_test.rb
+6
-5
未找到文件。
actionpack/lib/action_controller/metal/request_forgery_protection.rb
浏览文件 @
79d50ce3
...
...
@@ -240,6 +240,8 @@ def non_xhr_javascript_response?
content_type
=~
%r(
\A
text/javascript)
&&
!
request
.
xhr?
end
AUTHENTICITY_TOKEN_LENGTH
=
32
# Returns true or false if a request is verified. Checks:
#
# * is it a GET or HEAD request? Gets should be safe and idempotent
...
...
@@ -247,13 +249,73 @@ def non_xhr_javascript_response?
# * Does the X-CSRF-Token header match the form_authenticity_token
def
verified_request?
!
protect_against_forgery?
||
request
.
get?
||
request
.
head?
||
form_authenticity_token
==
form_authenticity_param
||
form_authenticity_token
==
request
.
headers
[
'X-CSRF-Token'
]
valid_authenticity_token?
(
session
,
form_authenticity_param
)
||
valid_authenticity_token?
(
session
,
request
.
headers
[
'X-CSRF-Token'
])
end
# Sets the token value for the current session.
def
form_authenticity_token
session
[
:_csrf_token
]
||=
SecureRandom
.
base64
(
32
)
masked_authenticity_token
(
session
)
end
# Creates a masked version of the authenticity token that varies
# on each request. The masking is used to mitigate SSL attacks
# like BREACH.
def
masked_authenticity_token
(
session
)
one_time_pad
=
SecureRandom
.
random_bytes
(
AUTHENTICITY_TOKEN_LENGTH
)
encrypted_csrf_token
=
xor_byte_strings
(
one_time_pad
,
real_csrf_token
(
session
))
masked_token
=
one_time_pad
+
encrypted_csrf_token
Base64
.
strict_encode64
(
masked_token
)
end
# Checks the client's masked token to see if it matches the
# session token. Essentially the inverse of
# +masked_authenticity_token+.
def
valid_authenticity_token?
(
session
,
encoded_masked_token
)
return
false
if
encoded_masked_token
.
nil?
||
encoded_masked_token
.
empty?
begin
masked_token
=
Base64
.
strict_decode64
(
encoded_masked_token
)
rescue
ArgumentError
# encoded_masked_token is invalid Base64
return
false
end
# See if it's actually a masked token or not. In order to
# deploy this code, we should be able to handle any unmasked
# tokens that we've issued without error.
if
masked_token
.
length
==
AUTHENTICITY_TOKEN_LENGTH
# This is actually an unmasked token. This is expected if
# you have just upgraded to masked tokens, but should stop
# happening shortly after installing this gem
compare_with_real_token
masked_token
,
session
elsif
masked_token
.
length
==
AUTHENTICITY_TOKEN_LENGTH
*
2
# Split the token into the one-time pad and the encrypted
# value and decrypt it
one_time_pad
=
masked_token
[
0
...
AUTHENTICITY_TOKEN_LENGTH
]
encrypted_csrf_token
=
masked_token
[
AUTHENTICITY_TOKEN_LENGTH
..-
1
]
csrf_token
=
xor_byte_strings
(
one_time_pad
,
encrypted_csrf_token
)
compare_with_real_token
csrf_token
,
session
else
false
# Token is malformed
end
end
def
compare_with_real_token
(
token
,
session
)
# Borrow a constant-time comparison from Rack
Rack
::
Utils
.
secure_compare
(
token
,
real_csrf_token
(
session
))
end
def
real_csrf_token
(
session
)
session
[
:_csrf_token
]
||=
SecureRandom
.
base64
(
AUTHENTICITY_TOKEN_LENGTH
)
Base64
.
strict_decode64
(
session
[
:_csrf_token
])
end
def
xor_byte_strings
(
s1
,
s2
)
s1
.
bytes
.
zip
(
s2
.
bytes
).
map
{
|
(
c1
,
c2
)
|
c1
^
c2
}.
pack
(
'c*'
)
end
# The form's authenticity parameter. Override to provide your own.
...
...
actionpack/test/controller/request_forgery_protection_test.rb
浏览文件 @
79d50ce3
...
...
@@ -125,8 +125,9 @@ def form_authenticity_param
module
RequestForgeryProtectionTests
def
setup
@token
=
"cf50faa3fe97702ca1ae"
SecureRandom
.
stubs
(
:base64
).
returns
(
@token
)
@controller
.
stubs
(
:form_authenticity_token
).
returns
(
@token
)
@controller
.
stubs
(
:valid_authenticity_token?
).
with
{
|
_
,
t
|
t
==
@token
}.
returns
(
true
)
@controller
.
stubs
(
:valid_authenticity_token?
).
with
{
|
_
,
t
|
t
!=
@token
}.
returns
(
false
)
@old_request_forgery_protection_token
=
ActionController
::
Base
.
request_forgery_protection_token
ActionController
::
Base
.
request_forgery_protection_token
=
:custom_authenticity_token
end
...
...
@@ -386,7 +387,7 @@ class RequestForgeryProtectionControllerUsingResetSessionTest < ActionController
end
test
'should emit a csrf-param meta tag and a csrf-token meta tag'
do
SecureRandom
.
stubs
(
:base64
).
returns
(
@token
+
'<=?'
)
@controller
.
stubs
(
:form_authenticity_token
).
returns
(
@token
+
'<=?'
)
get
:meta
assert_select
'meta[name=?][content=?]'
,
'csrf-param'
,
'custom_authenticity_token'
assert_select
'meta[name=?]'
,
'csrf-token'
...
...
@@ -467,7 +468,7 @@ def setup
super
@old_logger
=
ActionController
::
Base
.
logger
@logger
=
ActiveSupport
::
LogSubscriber
::
TestHelper
::
MockLogger
.
new
@token
=
"foobar"
@token
=
Base64
.
strict_encode64
(
SecureRandom
.
random_bytes
(
32
))
@old_request_forgery_protection_token
=
ActionController
::
Base
.
request_forgery_protection_token
ActionController
::
Base
.
request_forgery_protection_token
=
@token
end
...
...
@@ -479,7 +480,7 @@ def teardown
def
test_should_not_warn_if_form_authenticity_param_matches_form_authenticity_token
ActionController
::
Base
.
logger
=
@logger
SecureRandom
.
stubs
(
:base64
).
returns
(
@token
)
@controller
.
stubs
(
:valid_authenticity_token?
).
returns
(
:true
)
begin
post
:index
,
:custom_token_name
=>
'foobar'
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录