OTP(ワンタイムパスワード、2要素認証)とタイミング攻撃

(更新日: 2015/04/21)

今すぐできる、Webサイトへの2要素認証導入2要素認証のTOTPとHOTP、どちらがより安全か?で紹介したGoogleAuthenticatorですが、ソースコードを確認ところタイミング攻撃に脆弱でした。Pull Requestを後で送る予定ですが、利用される場合は脆弱性を修正してから使ってください。

タイミング攻撃とは?

タイミング攻撃とは、発熱、ノイズ、時間差、データサイズ(特に圧縮)などの副作用を用いたサイドサイチャネル攻撃の一種です。アルゴリズムなどの脆弱性を直接攻撃するのではなく、時間差などを統計的に処理することにより目的を達成(攻撃)することができます。

タイミング攻撃ではレスポンス時間の微妙な長さの違いを統計的に処理し、目的の秘密情報を盗み取ります。OTPでは数字しか使っておらず、桁数も6桁しかありません。脆弱な場合、タイミング攻撃がとても有効です。

問題のメソッド

GoogleAuthenticatorはOTPのチェックにverifyCodeメソッドを利用します。以下がそのコードです。

問題となる部分は

です。$calcuratedCodeと$codeは文字列です。このため、一文字一文字比較するため一文字ずつ間違っている場合と合っている場合の処理時間が異なります。非常に微妙な違いですが、一文字の正しい文字は数千リクエストもあれば検出可能です。※

6桁の数字なので単純なブルートフォース(総当たり)攻撃なら確実に秘密のOTPを盗むには100万リクエスト必要です。しかし、タイミング攻撃を利用すると数万リクエストもあれば盗めることになります。

HOTPの一時パスワードは使用しない限り新しいパスワードに更新されません。HOTPであればリスクがとても高い状態になります。

幸い(?)な事にGoogleAuthenticatorはTOTPしかサポートしていないので、タイミング攻撃に脆弱なコードの影響はHOTPより小さいです。

※ バイト単位で比較されるかはlibcのmemcmp()の実装によります。

 

コードの修正

タイミング攻撃に対する脆弱性は秘密情報をタイミング攻撃な脆弱な方法で”一文字ずつ”比較していることが原因です。

PHP 5.6以降であれば

をタイミングセーフな文字列比較関数であるhash_equals関数を使えば安全です。

$calculatedCode、$code共に6桁の整数です。PHP 5.6未満であれば整数として比較すればタイミングセーフになります。

もう少し防御的に$codeが意図した長さであるか確認した方が良いので、文字列の長さもチェックして以下のようにします。

 

まとめ

ソースコード検査はこのように内部仕様の問題を検出するにはとても効果的です。ソースコード検査ツールは多くありますが、このようなタイミング攻撃に対する脆弱性は検出できません。

弊社もソースコード検査を行っています。ソースコード検査が必要な場合はお問い合わせください。

 

参考:gitのglibcのmemcmp()は以下のような感じで実装されています。このブログによると2010年の段階では多くプラットフォームがタイミング攻撃に脆弱です。Linux 64bit環境memcmp()はバイト単位でタイミングに対して脆弱ではなかったようです。64bit環境のLinuxユーザーは神経質にならなくても良いでしょう。BSD系では別のアプローチで明示的にタイミングセーフなメモリ比較関数が用意されてる物があります。これは恐らく、64bit環境でも8バイト単位に分割してタイミング攻撃ができ、これも脆弱なのでいっそメモリ比較全体をタイミングセーフにしてしまうべき(この方が安全)、という考え方だと思います。環境によって影響は異りますが、認証などクリティカルなコードを書く開発者は今後もタイミング攻撃脆弱性に注意する必要があります。

 

Comments

comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です