Skip to content

Commit 859ca44

Browse files
committed
use secure string comparisons for basic auth username / password
this will avoid timing attacks against applications that use basic auth. Conflicts: activesupport/lib/active_support/security_utils.rb CVE-2015-7576
1 parent e694ac5 commit 859ca44

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

actionpack/lib/action_controller/metal/http_authentication.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'base64'
2+
require 'active_support/security_utils'
23

34
module ActionController
45
# Makes it dead easy to do HTTP Basic, Digest and Token authentication.
@@ -70,7 +71,11 @@ module ClassMethods
7071
def http_basic_authenticate_with(options = {})
7172
before_action(options.except(:name, :password, :realm)) do
7273
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
73-
name == options[:name] && password == options[:password]
74+
# This comparison uses & so that it doesn't short circuit and
75+
# uses `variable_size_secure_compare` so that length information
76+
# isn't leaked.
77+
ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
78+
ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
7479
end
7580
end
7681
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require 'digest'
2+
3+
module ActiveSupport
4+
module SecurityUtils
5+
# Constant time string comparison.
6+
#
7+
# The values compared should be of fixed length, such as strings
8+
# that have already been processed by HMAC. This should not be used
9+
# on variable length plaintext strings because it could leak length info
10+
# via timing attacks.
11+
def secure_compare(a, b)
12+
return false unless a.bytesize == b.bytesize
13+
14+
l = a.unpack "C#{a.bytesize}"
15+
16+
res = 0
17+
b.each_byte { |byte| res |= byte ^ l.shift }
18+
res == 0
19+
end
20+
module_function :secure_compare
21+
22+
def variable_size_secure_compare(a, b) # :nodoc:
23+
secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
24+
end
25+
module_function :variable_size_secure_compare
26+
end
27+
end

0 commit comments

Comments
 (0)