Rails CVE-2015-7576 で見る タイミングアタック(Timing Attack)
2016-01-31
Rails
セキュリティ
Rails 4.2.5.1 がリリースされました
いくつかのセキュリティフィックスのリリースです
あまり重要ではないですが、 CVE-2015-7576 の対応について見てみます
対象のコミットはこちらです
問題となったコード
http_basic_authenticate_with
を使ったBasic認証の際にタイミングアタックの脆弱性がありました
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
name == options[:name] && password == options[:password]
end
http_basic_authenticate_with
は以下のように Controllerに書くことで利用できます
http_basic_authenticate_with name: 'user', password: 'password'
そもそもタイミングアタックとはなんなのか?
以下の2つのコードはどちらが実行時間が早いでしょうか?
# コードA
'foo' == 'bar'
# コードB
'bar' == 'baz'
ms以下のレベルになるのですが、コードBのほうが実行時間が長くなります
- コードAは1文字目が異なるので、1文字目で比較判定を打ち切ります
- コードBは1文字目が同じで2文字目が異なるので 2文字目で比較判定を打ち切ります
そのため、コードBは1文字分だけ実行時間が長くなります
CVE-2015-7956 の修正コード
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
end
- `ActiveSupport::SecurityUtils.variable_size_secure_compare` を使用するように変更されている
- && から & のみとなっている
ActiveSupport::SecurityUtils.variable_size_secure_compare
入力文字列を SHA256 のハッシュ文字列に変換後 byte単位での比較をしています
def variable_size_secure_compare(a, b) # :nodoc:
secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
end
ハッシュ関数を通し、ActiveSupport::SecurityUtils.secure_compare
を利用することで
文字長の違いからのタイミングアタックを防止しているようです
まとめ
ユーザからの入力文字列とサーバ上のセキュアなもの(パスワードとか)を比較する際には
ActiveSupport::SecurityUtils.variable_size_secure_compare
を利用するようにしたほうが良さそう
その他
Rails Basic認証
等で検索すると以下のようなコードが散見されます
authenticate_or_request_with_http_basic do |user, pass|
user == 'user' && pass == 'pass'
end
(サーバのスペック向上に伴いタイミングアタック自体が成立しにくくなっているとはいえ)
バージョンアップ後のRails標準のhttp_basic_authenticate_with
を利用する
以下のように今回の対策と同じコードとしておく
authenticate_or_request_with_http_basic do |user, pass|
ActiveSupport::SecurityUtils.variable_size_secure_compare(name, 'user') &
ActiveSupport::SecurityUtils.variable_size_secure_compare(password, 'password')
end