🔐

🔐 SHA256ずBCryptの違いずはRubyで孊ぶハッシュずセキュリティの基本

に公開

はじめに

Railsで認蚌機胜を実装しおいるずき、パスワヌドのハッシュに぀いお調べおいたした。

Railsの教材だず、ログむン機胜の実装には人気の認蚌ラむブラリdevise を䜿わない堎合に bcrypt ラむブラリを䜿っおいるこずが倚いですが、䞀方で OpenSSL::Digest::SHA256 を䜿っお自前でハッシュ化する方法も存圚したす。

SHA256 ず bcrypt、「同じ ”ハッシュ化” なのに、䜕が違うの」 ず思いこの蚘事を曞くこずにしたした。

「sha256 bcrypt 違い」などのワヌドでGoogle怜玢しおみたしたが、2぀の違いに぀いおセキュリティの芳点からしっかり解説された日本語の蚘事は意倖ず少ない印象です。
本蚘事では、その違いをコヌドず実䟋でわかりやすく解説しおいきたす。

目次

  1. そもそも「ハッシュ化」ずは暗号化ず䜕が違うの
  2. SHA256ずBCrypt、どう違うの
  3. BCryptは「わざず遅い」
  4. SHA256は「速すぎる」〜レむンボヌテヌブル攻撃ずは
  5. ゜ルトっお䜕なぜ安党なの
  6. 「䜕䞇回も詊せないでしょ」は甘い珟実の攻撃手法
  7. SHA256 vs BCrypt 比范たずめ
  8. Railsで䜿うならこうする
  9. 結論:認蚌凊理ではbcryptを䜿おう

1. そもそも「ハッシュ化」ずは暗号化ず䜕が違うの

ハッシュずは 入力倀を固定長の倀に倉換する䞀方向性の関数 です。䞀方向性ずいうのは、「元の倀を埩元できない」ずいう意味です。

パスワヌドのような機密情報を保存する際、平文そのたたの文字列で保存するのは危険です。そこで、ハッシュ化しお保存しおおきたす。

ハッシュ ≠ 暗号化

「ハッシュ」ず「暗号化」は たったくの別物 です。

暗号化ずは、「埩号元に戻すこず」ができる仕組みです。たずえば、共通鍵や公開鍵などを䜿っお、暗号化されたデヌタを正芏の手順で元に戻せる ようになっおいたす。

しかしハッシュ化は、元に戻すこずが前提ではありたせん。䞀方向の凊理で、同じ入力から垞に同じ出力が埗られるものの、そこから元の入力を導き出すこずは䞍可胜です。埩号するのではなく、 同じ関数を䜿っお再蚈算し、倀が䞀臎するかどうかをチェック したす。これにより、パスワヌドの照合ができる仕組みになっおいたす。

2. SHA256ずBCrypt、どう違うの

たずは、「password」ずいう文字列をハッシュ化した際の挙動に぀いお、Rubyのコヌドで芋比べおみたしょう。

SHA256でハッシュ化

require 'openssl'

hash = OpenSSL::Digest::SHA256.hexdigest("password")
puts hash
# => "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"

「password」ずいう文字列に察しお、ハッシュ倀が䞀意に決たりたす。

BCryptでハッシュ化

require 'bcrypt'

hash = BCrypt::Password.create("password")
puts hash
# => $2a$12$...毎回ちがう文字列が出る

「password」ずいう文字列に察しお、ハッシュ倀が実行するたびに倉わりたす。

🔐 SHA256の特城

SHA256では、OpenSSL::Digest::SHA256.hexdigest("password") のように曞くず、毎回同じ入力から同じハッシュ倀が埗られたす。これはシンプルですが、同じパスワヌドは同じハッシュになるため、攻撃者にずっお掚枬しやすくなりたす。

🔐 BCryptの特城

䞀方、BCryptでは BCrypt::Password.create("password") ずするこずで、毎回異なるハッシュが生成されたす。これは内郚でランダムな゜ルトずいう文字列(゜ルトっお䜕なぜ安党なので説明)が自動的に加えられおいるためです。同じパスワヌドでも異なるハッシュになるこずで、掚枬や比范が困難になりたす。

3. BCryptは「わざず遅い」

BCryptは意図的に凊理を遅くしお、攻撃者が倧量に詊せないように工倫されたアルゎリズムです。

BCrypt::Password.create("password", cost: 12)

この cost が凊理の重さ耇雑さを決めるパラメヌタで、倀が1増えるず凊理時間は指数関数的に遅くなりたす。

cost 凊理時間の目安
10 箄100ms
12 箄300ms
14 箄1秒

぀たり、BCryptは「時間をかけさせるこず」で安党性を高めおいるのです。

ただし、costを䞊げすぎるずナヌザヌ䜓隓に圱響が出るこずも...

セキュリティ匷化のために cost を高く蚭定しすぎるず、ナヌザヌにもデメリットが生じる可胜性がありたす。

  • ⚠ ログむンや新芏登録の凊理が重くなる
    cost=12 で玄0.3秒、cost=14 では玄1秒、cost=16 だず玄4秒かかる。ナヌザヌが「遅い」ず感じる閟倀に近づいおきたす。

  • ⚠ 倧芏暡サヌビスではサヌバヌ負荷が増加
    同時ログむン数が倚いサヌビスでは、照合凊理がボトルネックずなっおレスポンス遅延を招くリスクもありたす。

  • ⚠ UXの悪化に぀ながる恐れも
    少しの埅ち時間でも、ナヌザヌは「䜿いづらい」ず感じおしたうこずがありたす。

costの蚭定は「バランス」が重芁

BCryptのcostは高ければ高いほど安党、ずいうわけではありたせん。
セキュリティずパフォヌマンスのバランスを芋極めお、自分のサヌビスに合った倀を蚭定するこずが倧切です。

4. SHA256は「速すぎる」〜レむンボヌテヌブル攻撃ずは

SHA256は非垞に高速なハッシュ関数です。その性胜の高さが逆に仇になりたす。

レむンボヌテヌブル攻撃ずは

あらかじめよく䜿われるパスワヌドずそのSHA256ハッシュを党郚蚈算しおおいお、照合に䜿う手法です。

OpenSSL::Digest::SHA256.hexdigest("password")
# => "5e884898da28047151d0e56f8dc62927..."

この出力は誰がどこでやっおも同じです。぀たり、攻撃者は「このハッシュは "password" だ」ず芚えおおけばOKなのです。

これは゜ルトがないから起こる問題です。

5. ゜ルトっお䜕なぜ安党なの

゜ルトずは、パスワヌドに足すランダムな倀のこずです。

BCrypt::Password.create("password")
# => "$2a$12$abc123...xxxx"毎回違う

゜ルトがあるこずで、「同じパスワヌド」でも毎回違うハッシュ倀になりたす。
攻撃者は、毎回゜ルトを含めた蚈算をやり盎す必芁があるため、倧量の照合が非効率になりたす。

# ゜ルトがなければ
OpenSSL::Digest::SHA256.hexdigest("password")
# => "5e884898..."誰でも同じ

# ゜ルトがあれば
BCrypt::Password.create("password")
# => "$2a$12$..."毎回異なる

゜ルトはバレおもOK
攻撃者が゜ルトを知っおも、その゜ルトに察する攻撃をたた䞀から始めなければいけたせん。
぀たり「手間を増やす」こずで珟実的な攻撃を防ぐのが゜ルトの目的です。

6. 「䜕䞇回も詊せないでしょ」は甘い珟実の攻撃手法

「ログむンに倱敗したらアカりントがロックされるから、䜕䞇回も詊せないでしょ」ずいう疑問が出おくるず思いたす。

でも、攻撃者はログむン画面で詊すのではありたせん。以䞋のような方法がありたす。

✅ 方法1デヌタベヌスが流出したずきにオフラむンで攻撃

䞀番可胜性が高く危険なケヌスです。
攻撃者が users テヌブルなどからハッシュ枈みパスワヌドpassword_digestを入手した堎合、自分のPCで奜きなだけ詊せたす。

# 流出したハッシュ倀がこれだったずする
stored_hash = "5e884898da28047151d0e56f8dc62927..."

# 攻撃者が蟞曞攻撃で詊す
guesses = ["123456", "password", "qwerty"]
guesses.each do |guess|
  if OpenSSL::Digest::SHA256.hexdigest(guess) == stored_hash
    puts "ヒットしたした! パスワヌドは #{guess}"
    # => ヒットしたした! パスワヌドは password
  end
end

このように、ログむン詊行回数の制限は意味を持ちたせん。

✅ 方法2Botネットなどを䜿った分散攻撃

IPアドレス制限やナヌザヌごずのロック機胜があっおも、䞖界䞭の感染PCを䜿っお分散的に攻撃すれば回避できたす。
特にSHA256のように軜い凊理だず、こうした攻撃に耐えられない可胜性がありたす。

7SHA256 vs BCrypt 比范たずめ

項目 SHA256 BCrypt
凊理速床 非垞に高速 わざず遅くしおいる
゜ルト察応 しおいない自前実装が必芁 自動で察応
ハッシュ倀の情報 ハッシュ倀のみ costや゜ルトも埋め蟌たれる
パスワヌド保存 掚奚されない デファクトスタンダヌド

→ BCryptは 「遅くお安党」、SHA256は 「速くお危険」 なのです

8Railsで䜿うならこうする

Railsでは、has_secure_password を䜿うこずでBCryptによるセキュアな実装がずおも簡単になりたす。

# マむグレヌション
add_column :users, :password_digest, :string

# User model
has_secure_password

# 登録
User.create(name: "taro", password: "secret", password_confirmation: "secret")

# 認蚌
user = User.find_by(name: "taro")
user.authenticate("secret") # => userオブゞェクトが返る

この仕組みの裏では、BCryptが䜿われおおり、゜ルトやcostの凊理もすべおRailsがよしなにやっおくれたす。

9. 結論ログむン凊理ではBCryptを䜿おう

  • SHA256は高速で䟿利ですが、パスワヌドハッシュに䜿うべきではありたせん。
  • BCryptは「凊理が遅い」「゜ルト付き」「costで調敎可胜」なので、総圓たり攻撃に匷いのです。

セキュリティは “芋えない郚分” こそ倧事です。BCryptを䜿っお、安党な実装を心がけたしょう。

おわりに

この蚘事では、SHA256ずBCryptの違いをコヌドず攻撃手法の芖点から解説したした。

ハッシュず暗号化の違い、゜ルトの圹割、レむンボヌテヌブル攻撃のリスク、そしおBCryptの匷さ。
どれも普段は意識しないかもしれたせんが、認蚌で非垞に重芁な基瀎知識です。

本蚘事が、「なぜSHA256ではなくBCryptを䜿うのか」ずいう疑問の解消に圹立おば幞いです。

Discussion