mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #24510 from vipulnsward/make-variable_size_secure_compare-public
Make variable_size_secure_compare public
This commit is contained in:
commit
0623b5d194
5 changed files with 37 additions and 19 deletions
|
@ -72,10 +72,10 @@ module ActionController
|
||||||
before_action(options.except(:name, :password, :realm)) do
|
before_action(options.except(:name, :password, :realm)) do
|
||||||
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
|
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
|
||||||
# This comparison uses & so that it doesn't short circuit and
|
# This comparison uses & so that it doesn't short circuit and
|
||||||
# uses `variable_size_secure_compare` so that length information
|
# uses `secure_compare` so that length information
|
||||||
# isn't leaked.
|
# isn't leaked.
|
||||||
ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
|
ActiveSupport::SecurityUtils.secure_compare(name, options[:name]) &
|
||||||
ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
|
ActiveSupport::SecurityUtils.secure_compare(password, options[:password])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -350,10 +350,7 @@ module ActionController
|
||||||
# authenticate_or_request_with_http_token do |token, options|
|
# authenticate_or_request_with_http_token do |token, options|
|
||||||
# # Compare the tokens in a time-constant manner, to mitigate
|
# # Compare the tokens in a time-constant manner, to mitigate
|
||||||
# # timing attacks.
|
# # timing attacks.
|
||||||
# ActiveSupport::SecurityUtils.secure_compare(
|
# ActiveSupport::SecurityUtils.secure_compare(token, TOKEN)
|
||||||
# ::Digest::SHA256.hexdigest(token),
|
|
||||||
# ::Digest::SHA256.hexdigest(TOKEN)
|
|
||||||
# )
|
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
|
|
|
@ -369,7 +369,7 @@ module ActionController #:nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare_with_real_token(token, session) # :doc:
|
def compare_with_real_token(token, session) # :doc:
|
||||||
ActiveSupport::SecurityUtils.secure_compare(token, real_csrf_token(session))
|
ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, real_csrf_token(session))
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_per_form_csrf_token?(token, session) # :doc:
|
def valid_per_form_csrf_token?(token, session) # :doc:
|
||||||
|
@ -380,7 +380,7 @@ module ActionController #:nodoc:
|
||||||
request.request_method
|
request.request_method
|
||||||
)
|
)
|
||||||
|
|
||||||
ActiveSupport::SecurityUtils.secure_compare(token, correct_token)
|
ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, correct_token)
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
* Changed default behaviour of `ActiveSupport::SecurityUtils.secure_compare`,
|
||||||
|
to make it not leak length information even for variable length string.
|
||||||
|
|
||||||
|
Renamed old `ActiveSupport::SecurityUtils.secure_compare` to `fixed_length_secure_compare`,
|
||||||
|
and started raising `ArgumentError` in case of length mismatch of passed strings.
|
||||||
|
|
||||||
|
*Vipul A M*
|
||||||
|
|
||||||
* Make `ActiveSupport::TimeZone.all` return only time zones that are in
|
* Make `ActiveSupport::TimeZone.all` return only time zones that are in
|
||||||
`ActiveSupport::TimeZone::MAPPING`.
|
`ActiveSupport::TimeZone::MAPPING`.
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,12 @@ require "digest/sha2"
|
||||||
|
|
||||||
module ActiveSupport
|
module ActiveSupport
|
||||||
module SecurityUtils
|
module SecurityUtils
|
||||||
# Constant time string comparison.
|
# Constant time string comparison, for fixed length strings.
|
||||||
#
|
#
|
||||||
# The values compared should be of fixed length, such as strings
|
# The values compared should be of fixed length, such as strings
|
||||||
# that have already been processed by HMAC. This should not be used
|
# that have already been processed by HMAC. Raises in case of length mismatch.
|
||||||
# on variable length plaintext strings because it could leak length info
|
def fixed_length_secure_compare(a, b)
|
||||||
# via timing attacks.
|
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
||||||
def secure_compare(a, b)
|
|
||||||
return false unless a.bytesize == b.bytesize
|
|
||||||
|
|
||||||
l = a.unpack "C#{a.bytesize}"
|
l = a.unpack "C#{a.bytesize}"
|
||||||
|
|
||||||
|
@ -19,11 +17,15 @@ module ActiveSupport
|
||||||
b.each_byte { |byte| res |= byte ^ l.shift }
|
b.each_byte { |byte| res |= byte ^ l.shift }
|
||||||
res == 0
|
res == 0
|
||||||
end
|
end
|
||||||
module_function :secure_compare
|
module_function :fixed_length_secure_compare
|
||||||
|
|
||||||
def variable_size_secure_compare(a, b) # :nodoc:
|
# Constant time string comparison, for variable length strings.
|
||||||
secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
|
#
|
||||||
|
# The values are first processed by SHA256, so that we don't leak length info
|
||||||
|
# via timing attacks.
|
||||||
|
def secure_compare(a, b)
|
||||||
|
fixed_length_secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
|
||||||
end
|
end
|
||||||
module_function :variable_size_secure_compare
|
module_function :secure_compare
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,4 +13,15 @@ class SecurityUtilsTest < ActiveSupport::TestCase
|
||||||
assert ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "a")
|
assert ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "a")
|
||||||
assert_not ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "b")
|
assert_not ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "b")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_fixed_length_secure_compare_should_perform_string_comparison
|
||||||
|
assert ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "a")
|
||||||
|
assert !ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "b")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fixed_length_secure_compare_raise_on_length_mismatch
|
||||||
|
assert_raises(ArgumentError, "string length mismatch.") do
|
||||||
|
ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "ab")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue