セキュリティは簡単ではありません。

こんにちは。


sfDoctrineGuardPluginのバグを修正しようとしていることがわかったかなり興味深い記事の翻訳を紹介します。 幸いなことに、約2週間前、ここに書かれたすべてはすでに修正されており、危険なものは何もありませんが、プラグインの更新を頻繁に監視せず、この脆弱性について知らない人の注意を喚起したいと思います。





最終更新:1年後(翻訳者のメモの後:エラーが最初に公開された後)、両方のプラグインが最終的に更新され、より良いランダムキージェネレーターが使用されます。



セキュリティは簡単ではありません。 プログラマは、乱数や識別子生成の既製ライブラリなどを残す必要があります(または、少なくともより良い方法を開発します)。 多くのプロジェクトがこれを難なくマスターしました。



約6か月前に会った関数の例として、これについて話しましょう。

function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  1. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  2. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  3. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  4. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  5. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  6. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  7. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  8. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  9. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }



  10. function generateRandomKey( $len = 20 ) { $string = '' ; $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; for ( $i = 1 ; $i < = $len ; $i ++) { $string .= substr( $pool , rand( 0 , 61 ), 1 ); } return md5( $string ); }





これは本当の逸品です。プログラマーがしてはいけないことすべてに焦点を当てるように書かれているようです。

エラー1
mt_rand ()の代わりにrand()を使用します。 PHPプログラマはこれを知っている必要があります。

エラー2
sha1 ()の代わりにmd5()を使用します。 PHPプログラマはこれを知っている必要があります。

エラー3
20文字のランダムな文字列を作成し、それを32文字の文字列にハッシュすることは、少し馬鹿げています。 もちろん、ハッシュにはさまざまな文字が含まれていますが、入力には7.04423e +35の異なる値があり、出力には3.40282e +38があります。

エラー4
rand()を複数回呼び出します。 これは、 擬似乱数ジェネレーターがどのように機能するかを無視することを意味します。 ソースが変更されるまで、前の番号に応じて、次の番号が何であるかを簡単に推測できます。 複数の関数呼び出しで「よりランダム」になりません。

エラー5
非常に限られた範囲で乱数を選択してください。 また、ハッシュ関数に切り替えた後に使用しないのに、なぜ英数字を選択するのですか? これは非常によく考えられていないようです。

エラー6
既存のすべてのレインボーテーブルに存在する英数字をmd5の文字列として使用します。

エラー7
chr()を聞いたことがありますか?

エラー8
なぜ車輪を再発明するのですか? 極端な場合、この理由があれば、それについて書いてください(この関数はコメントを必要としません)。



結果を確認しなくても、プログラマはこの関数を完全に書き換える必要があることを知っている必要があります。



どのように見えるかを見てみましょう。





  1. 関数 generateRandomKey()
  2. {
  3. return base_convert(sha1(uniqid(mt_rand()、 true ))、16、36);
  4. }


どうやってこれに到達しましたか? 基本的に、PHPのドキュメントを読んで、乱数ジェネレーターを作成するのではなく、それを使用します。



base_convert()の使用は実際には重要ではありません。主にデータベースフィールドが短すぎたためです( sha1()から何も失われません)。 実際には、 sha1()なしでそれがより良いでしょう、私たちは美のためだけにそれを使用します。



uniqueid()mt_rand()から取得した値を取り、 それにランダムな一意の値を追加します(ただし、予測可能な範囲では、両方の関数を使用するのが理にかなっています)。 これはPHPのドキュメントで推奨されており、これで十分です。



今、あなたはおそらくこのコードをどこで見つけたかを自問するでしょう。



この関数はsymfonyフレームワークのsfGuardPluginおよびsfDoctrineGuardPluginにあります。 この機能はほとんど当初からありますが、 より悪い ものでし 。 これらは、公式ドキュメントで承認された最も一般的に使用されるプラグインです。



これはどういう意味ですか? 一部のシステムでは、ブルートフォースを使用して任意のユーザーとしてログインするのが非常に簡単です。 または、衝突の可能性が非常に高いため、ユーザーが誤って別のユーザーとしてログインする可能性があります。



まあ、それが本当なら、誰かがそれに気付くべきだった! 私はおそらく攻撃者ではありません。

実際、そうです。 古いDebianサーバーでこれをすべて再現する機会があり、このサーバーには、ユーザーが別のユーザーとしてログインしていると何度も不満を言うサイトがありました(このサーバーが失敗し、現在プロジェクトが修正されている機能)。 もちろん、Windows XPで仮想マシンで再生しようとしました(これは、乱数ジェネレーターの欠陥を使用してPHPを取得する最も簡単な方法だったためです)。もちろん、成功しました。 これらの2つのマシンで多くの衝突が発生したため、おそらくより高度なシステムでも、エラーは多少の労力で使用できます。



なぜこれをしているのですか?

私はこれを6ヶ月前に報告したが、これにはほとんど注意が払われなかったため。

symfonyは素晴らしいと思いますが、セキュリティは貧弱です(ただし、他のコメントは、コードではなくsymfonyに触発された、より標準的なプログラミングやホスティングのプラクティスに関するものです)。




このトピックには、奇跡の機能の仕事の例が示されている別の投稿があります。



All Articles