web-dev-qa-db-ja.com

最も一般的なパスワードソルティング方法は何ですか?

Sunの連中がパスワードハッシュのソルトとしてログイン名を使用していることを知りました。これは一般的なアプローチですか?最も一般的なソルト値は何ですか?

15
Federico Elles

ログイン名をソルトとして使用することは一般的ですが、実際には推奨されません。これはジョブの一部のみを実行します。ソルトのポイントは、ハッシュされたパスワードのすべてのインスタンス間で可能な限り一意であることです。これにより、試行を並列攻撃として阻止します(複数のハッシュされたパスワードを同時に攻撃し、Rainbowテーブルなどの事前計算されたテーブルを使用して...は並列攻撃です)。異なるシステムでは、複数のユーザーが同じログイン名を共有している場合があります(そこにはジョーンズとスミスがたくさんいます)。また、特定のユーザーは自分の名前を保持したままパスワードを変更できます。しかし、古いパスワードでも攻撃者にとって貴重です(古いパスワードは、ユーザーが次にパスワードを変更するように指示されたときに再利用するパスワードであることが多いためであるだけでなく、多くのユーザーが他のシステムでも同じパスワードを使用する場合) 。

ソルトを生成する推奨方法は、優れた乱数ジェネレータ(理想的には暗号学的に強力なRNG)を使用して、ランダムなバイトの束を生成することです。ソルトが十分に長い場合(16バイト以上)、これにより、圧倒的な確率で必要な一意性が確保され、手間がかかりません(たとえば、既存のソルトのデータベースを検索する必要がありません)。

この推奨される方法が「最も一般的な」方法である、または間もなくその方法になることを願うだけです。

15
Thomas Pornin

以下は、パスワードをソルトおよびハッシュするための適切なシステムです。覚えておくべき点がいくつかあるので、長く見えるのです。これは、ソルトハッシュに関してがすべきことの典型的な例です。 Sunの機能については説明しません。

ソルトとパスワードは、生のバイト(byte[]unsigned char*など)、使用する言語が他の形式のテキスト文字列を処理する場合。

ソルトを生成するために、暗号的に強力な疑似乱数ジェネレータを使用して新しいソルトを生成しましょう。 Rubyでは、そのライブラリは便宜上securerandomと呼ばれます。ほとんどの言語には乱数ジェネレーターも付属していますが、saltには十分ではありません。

基本的なハッシュアルゴリズムとして SHA256 を使用しましょう。すべてのハッシュアルゴリズムには、ハッシュ関数の出力のビット単位のサイズである出力サイズがあります。すべてのハッシュアルゴリズムには、出力サイズとは異なる特徴的な内部ブロックサイズもあります。ハッシュアルゴリズムのブロックサイズと同じ大きさのソルトを使用します。これは、ハッシュする前にパスワードに追加できるエントロピーの最大量であるためです。基礎となるハッシュアルゴリズムのブロックサイズよりも大きいソルトを使用する場合、HMACは単純にソルトをハッシュして、小さいソルトを取得し、エントロピーを減らしてから、パスワードと混合します。 SHA256のブロックサイズは512ビット(= 64バイト)なので、64バイトのソルトを使用します。

SHA256の代わりに [〜#〜] hmac [〜#〜] -SHA256を直接使用してみましょう。これは、パスワードを安全に保つためにもう少し作業を行います。 saltをパスワードの前に付加するのではなく、HMAC-SHA256のキーパラメータとして使用します。 HMAC-SHA256はSHA256をラップし、ソルトとパスワードをマージするために少し余分な作業を行います。

最後に、SHA-256などのハッシュアルゴリズムは高速になるように設計されています。私たちのコードが全体的に行うことは何でも、それはその時間の1%をユーザーの認証と99%のその他のものに費やすことになるでしょう。攻撃者がパスワードファイルのコピーを入手した場合、攻撃者のコードはその時間の100%を費やしてパスワードを総当たり攻撃する可能性があります。それでは、アルゴリズム全体を超低速にします。それは、コードの残りの部分に影響を与えるほど遅くはありませんが、攻撃者を阻止するのに十分なほど低速です。作業係数(16の場合がある)と呼ばれるパラメーターを取り、HMAC-SHA256 2 ^作業係数の回数(例では65536回)を繰り返します。作業係数が2の場合、それは次のようになります。

HMAC-SHA256(salt,
  HMAC-SHA256(salt,
    HMAC-SHA256(salt,
      HMAC-SHA256(salt,
        password
      )
    )
  )
)

Rubyの優れたシンプルなソリューション:

require "securerandom"
require "openssl"

# method for generating a salt and computing a hashed
# version of a password
def salt_hash(password, work_factor)

  # get raw bytes from the password string; only needed in Ruby >= 1.9
  password = password.force_encoding(Encoding::ASCII_8BIT) if defined?(Encoding)

  # use SHA256 as the underlying hash algorithmn
  hash = OpenSSL::Digest::SHA256.new

  # generate a salt as long as the hash algorithm's block size
  # using a cryptographically strong pseudo-random number generator
  salt = SecureRandom.random_bytes(hash.new.block_length)

  # use HMAC, feeding it two parameters: the salt and the
  # underlying hash; since the underlying hash is SHA256,
  # this turns it into HMAC-SHA256
  hmac = OpenSSL::HMAC.new(salt, hash)

  # iterate running HMAC-SHA256 on the password 2^work-factor
  # times to make this function slow enough to discourage an
  # attacker, but not too slow as to make the service unresponsive
  iterations = 2 ** work_factor
  iterations.times do
    password = hmac.digest(password)
  end

  # return the salt and the hashed password to whoever called
  # this method
  {:salt => salt, :hash => password, :work => work_factor}

end

# how to call the method
salt_hash("seekrit", 16)
# and the output would be
 => {:salt => "raw bytes", :hash => "raw bytes", :work => 16}
7
yfeldblum