web-dev-qa-db-ja.com

MySQL ENCRYPTソルトはランダムではありませんか?

今でもENCRYPT()を使用する理由はほとんどないことを知っています。bcryptはほぼどこにでもあり、MySQLは_SHA1_などのより良いハッシュを提供します。

しかし、MySQL 5.6.12(OpenSuSE 13.1、x64)でENCRYPT()を使用していると、最初にエントロピープールが枯渇していることが原因であるという出力の異常に気付きました(それは)可能性があります、その後、接続間でリークされている塩におそらく。

検証の結果、そうではなかったことが判明しました。

むしろ、ソルトはUNIXタイムスタンプから派生します。したがって、同じ秒内にENCRYPT()を2回呼び出すと、同じソルトが生成され、ソルトは1時間、12分、16秒ごとに正確に繰り返されます。

_while(true); do \
    echo "SELECT NOW(),ENCRYPT('test');" \
    | mysql test | grep -v ENCRYPT; \
done | uniq -c

 54 2014-05-14 00:13:16     w5kVzeZkJCcqM
148 2014-05-14 00:13:17     x5/h3KfsBkEYk
150 2014-05-14 00:13:18     y5thvRDxwJgM6
145 2014-05-14 00:13:19     z5RL9IZ0..XH6
141 2014-05-14 00:13:20     .6asQOJRqB1i2
130 2014-05-14 00:13:21     /6J1nHNWbi6Ac
124 2014-05-14 00:13:22     06NT9j.EegRJs
_

もちろん、私は自分のソルトをできますランダムなソースから取得できます-TO_BASE64(CONCAT(CHAR(Rand()*256),CHAR(Rand()*256)))または何か、元のソルトと同じ文字範囲を取得する必要があります最初の2バイトなので、ENCRYPT()が独自のソルトを作成するのは、最後の努力で十分です。

また、塩はsecretであるとは想定されていないため、事前に知ることはそれほど大きな問題ではないかもしれません。

それでも、ソルティングにtime()を使用することは、私にとってあまり良いオプションとは思えません( この答え もこれを確認します)。

明らかなものがないのですか?おそらくこの動作は何らかの方法で構成可能ですか(再コンパイルは別として)?これは既知の機能ですか(GoogleまたはMySQL KBで参照を見つけることができませんでした)?

3
LSerni

MySQL ENCRYPT() 関数は、encryptionとまったく異なるため、非常に不適切な名前が付けられています。これはOSが提供するcrypt()関数のラッパーであり、同様に不適切な名前が付けられています。これはパスワードハッシュ関数で、たまたまブロック暗号から派生したものです [〜#〜] des [〜#〜] しかし、「派生」は重要な言葉です。アルゴリズムが変更され、特に、提供されたパスワードは暗号化されるデータとしてではなく、暗号化キーとして使用されます。特に、変換は元に戻せません。パスワードを明らかにするdecrypt()はありません。

たまたま、従来のDESベースのcrypt()関数は、ENCRYPT()を基にしており、12ビットのソルトを含んでいます。塩のポイントは、実行可能な限り、それ自体を繰り返すことです。ただし、12ビットのソルトの場合、可能なソルト値は4096しかないため、ソルトの再利用は避けられません。一方、塩は秘密である必要はなく、ランダムであったり、予測不可能であったりする必要はありません。時間ベースの割り当て戦略は、他のどの戦略よりも優れています。ランダムな塩の選択は、その点ではるかにうまくいきません。同じ秒内の2つの呼び出しは、同じソルトがずさんなことを意味します。 ENCRYPT()をバッチ形式で使用して、多数のパスワードを短時間でハッシュする必要がある場合は、逆効果になることがあります。それを除けば、現在の時刻をソルトとして使用することには何の問題もありません。

ここでの本当の弱点は、DESベースのcrypt()関数を使用していることです。それにはいくつかの深刻な欠点があります:

  • パスワードは8文字に制限されていますASCII文字(後続の文字、および各バイトの上位ビットは無視されます)。
  • 塩スペースが非常に小さいため、無視できない塩の再利用が避けられません。
  • 速度が速すぎて快適ではありません。反復の内部数は固定されていて低く、ビットスライシングテクニックを使用することで、並列攻撃のコンテキストで関数を大幅に高速化できます。

あなたがその関数を使用するという不運な決定をした場合、時間ベースのソルトはあなた自身が負った悲惨さを顕著に増加させません。

2
Thomas Pornin

Mysqlソース(item_strfunc.cc)を見ると、正しいように見えます。

String *Item_func_encrypt::val_str(String *str) { ... #ifdef HAVE_CRYPT char salt[3],*salt_ptr; if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return make_empty_result(); if (arg_count == 1) { // generate random salt time_t timestamp=current_thd->query_start(); salt[0] = bin_to_ascii( (ulong) timestamp & 0x3f); salt[1] = bin_to_ascii(( (ulong) timestamp >> 5) & 0x3f); salt[2] = 0; salt_ptr=salt; }

ランダムソルトはクエリの開始時間から直接生成されます:

  • timestamp=current_thd->query_start()
1