2022年2月20日日曜日

パスワードの制限が厳しいとハッシュ化していない可能性が高い理由

以前、イライラするパスワード登録画面5選という記事でこんな趣旨のことを書きました。

パスワードが「8文字以上16文字以下で入力してください」とか「英数字で入力してください」のように制限が厳しいサービスは、パスワードをハッシュ化せずにそのままDBに保存している可能性が高い

生パスワードをそのまま保存する危険性については言わずもがなですが、上記の内容について先日「なんで?」という質問を受けたので、この場でも書いておきます。

おことわり

まず最初に断っておきますが、「文字数や文字種の制限が厳しい」と「生パスワードを保存している」はイコールではありません。

逆に「制限がゆるい=きちんとハッシュ化している」でもありません。あくまで傾向や可能性(尤度)の話です。

で、根拠。

一言で言えば、ハッシュ化していれば文字数や文字種の制限は不要だからです。不要なはずの制限をわざわざ設けているということは、そもそもハッシュ化していない可能性が高いという話です。

ハッシュ化している場合

パスワードがどんなに長くても、ハッシュ化してしまえば一定サイズに収まるので元のパスワードの長さを制限する理由はありません。また、ハッシュ化されたパスワードはバイナリー列になるので、きちんとハッシュ化しているサービスはどんな値が来ても問題ないようにDBに格納する際は適切にエスケープをしたり、hexstringやBase64などでエンコードしているはずで、文字種を制限する理由もありません。

まあ、あまりにも長いパスワードはハッシュ値の算出にCPUパワーを使うので、100文字程度に抑えるくらいの制限は必要かもしれませんが、必要な制限といえばせいぜいそれくらいでしょう。あとはプラットフォームによってエンコード方法が違う可能性があるのでマルチバイト文字を禁止するくらいでしょうか。

生パスワードをそのまま保存している場合

この場合、格納できるパスワードの長さがDBのパスワード保存に使うカラムのサイズに左右されます。パスワード保存用のカラムに16文字分しか用意していなければ、当たり前ですがパスワードも16文字までしか受け付けられません。

また、SQLインジェクションを警戒して文字種を制限する場合があります。セキュリティーの知識があって素晴らしい・・・と言いたいところですが、そもそもハッシュ化していればSQLインジェクションの警戒自体が不要です。

もう一度おことわり

念のためもう一度いっておきますが、これらあくまで傾向や可能性の話です。100文字格納できる領域を確保していて適切にエスケープ処理をしていれば、生パスワードをそのまま保存しつつ文字数や文字種の制限を緩めることもできます。

逆に、内部で適切にハッシュ化していても、言語やフレームワークが特殊文字を変換してしまうなどの理由で特殊文字を除外する場合もあるかもしれません。たとえば古いPHPでは入力値を自動的にクォートする設定があります。これが有効になっているとエスケープした特殊文字をハッシュ化してしまいややこしいことになるので、あえて特殊文字を許可しない仕様にしているという可能性もあります。

また、リクエストに特殊文字が含まれているとWAFが勝手に弾いてしまうので許可しない場合もあるでしょう。

こういった理由で、文字種に関しては「制限が強い=生パスワードを保存している」とは一概に言えないのですが、まあさすがに文字数の制限が厳しい場合は疑ったほうがいいでしょう。

0 件のコメント:

コメントを投稿