やられアプリ BadTodo - 17.1 認証(パスワードの強度・ログアウト)

前回:やられアプリ BadTodo - 16 バッファオーバーフロー - demandosigno

これまでに「IPA 安全なウェブサイトの作り方 第7版」の11項目を検査してきました。

BadTodoは「ウェブ健康診断仕様」の診断項目も網羅しています。 この内、安全なウェブサイトの作り方と重複していない残りの2項目(認証・クローラへの耐性)について検査します。

認証

「ウェブ健康診断仕様」p.16より。
パスワードの強度とログアウト時の挙動について、次の6項目を確認します。

1.パスワードの最大文字数が8 文字以上確保されているか
2.パスワードの文字種が数字のみ、英字のみに限定されていないか
3.パスワードが入力時に伏字になっているか
4.パスワード間違いの際のメッセージは適切か
5.ログアウト機能はあるか、適切に実装されているか
6.意図的に 10 回パスワードを間違える

1.パスワードの最大文字数が8 文字以上確保されているか

「8文字未満」の場合、強度が弱く問題ありとされます。

「マイページ」→パスワード「変更」画面から、パスワードを変更してみます。「a」1文字の入力としました。

変更をクリックすると「パスワードは4文字以上で指定してください」と出ました。

1,2,3文字では同様のエラーでしたが、4文字「aaaa」で登録することができました。

8文字未満であるため問題あります。

「マイページの全体情報変更画面」「新規会員登録画面」でも同様に4文字で登録可能でした。

このように(changepwddo.php, editprofiledo.php, adduser.php)の3リクエストを確認する必要がありますが、以降はパスワード変更画面での例を示します。

2.パスワードの文字種が数字のみ、英字のみに限定されていないか

「数字のみ、英字のみの場合」問題ありとされます。

「aa11」「aa-11*」などでも登録できましたので、限定されているというわけではないのでOKです。この辺りの認識が曖昧ですので後日調べます。

→追記。NIST SP800-63-3におけるパスワードの要件は次のようになっていました。

  • このガイドラインに基づいて唯一必要な制限は、パスワードの長さが8文字以上であることです」(少なくとも 64文字であることを許可すべき)
  • 「すべての印刷 ASCII 文字を許容すべきである。Unicode文字も受け入れるべきである」(英大文字、英小文字、数字、記号が使用可能)
  • 「辞書単語や、繰り返しまたは連続した文字(例えば 'aaaaaa', '1234abcd')。サービス名・ユーザー名およびその派生語などは拒否の理由を提示し、別の値を選択するよう要求しなければならない」
  • 他の構成規則(たとえば、異なる文字タイプの混合を要求したり、連続して繰り返される文字列を禁止したりする)を課すべきでない
  • 「パスワードを定期的に変更することを要求すべきではない」

など。つまり従来の規則のように大文字・小文字・数字・記号を全部混ぜることを強要する必要はありませんでした。そうすると単純な"abcdefg"などが許されるのかとなりますが、そちらは3番目の「辞書登録単語やIDと同じ文字列のような安易なパスワードを受け付けない」によって担保します。

NIST Special Publication 800-63B
NISTの新しいパスワードルールブック: 更新版ガイドラインによる、メリットとリスクがあります
世界の電子認証基準が変わる:NIST SP800-63-3を読み解く :: GMOトラスト・ログイン ブログ | シングルサインオン(SSO)や認証に関する話題

3.パスワードが入力時に伏字になっているか

「伏字になっていない場合、問題あり」とされています。入力時の画面を肩越しに覗かれるなどして漏洩する可能性を問題視しています。

「新規会員登録画面」伏字になっています。問題ありません。

「パスワード変更画面」「マイページ変更画面」問題ありません。

「ログイン画面」伏字になっていません。問題ありです。

コード上 input type="text" となっている所を他の場所に合わせて input type="password" とするだけですので直しましょう。
ただ「実際問題後ろから覗き込む人などまずいない」「その気になればキーボードからでも読み取れる」「入力ミスの多発」からの「安易なパスワード設定」に繋がるなど、隠せばよいとは一概には言えません。
そこで巷で見かける方法としては、伏字にした上で「パスワードを表示する」という項目にチェックを入れると文字列を確認できるようになっていることが多いです。
(ただ、ブラウザの機能としてではなくアプリケーション側で「パスワード表示ボタン」を独自実装するのは危険が伴います)

4.パスワード間違いの際のメッセージは適切か

「ユーザ ID とパスワードのどちらが間違いか分かるようなメッセージの場合」問題ありです。

ログイン時、ID、パスワードをそれぞれ間違ってみます。
「そのユーザーは登録されていません」「パスワードが違います」と出ました。

これらのメッセージから「そのIDは存在しない」と確定でき攻撃者へのヒントとなります。一概には言えませんが、一般的には「IDまたはパスワードが違います」と表示するのが良いとされています。
(ログインIDとパスワードがそれぞれ1万通りある場合、IDの間違い(存在しないID)が分かるなら2万通りの探索で済みますが、双方分からない場合1万×1万=1億通りすべて試すことになります)
(しかしこれもまた「どちらが間違ったのか分からないのは不便」「そもそもログインIDが公開されているサイトには無意味」なため、IDの確認を先に済ませその後にパスワードの確認を行うといったようにIDとパスワードを別々に入力させるサイトが増えています)
(後述の徳丸さんの講演資料「セキュリティの都市伝説を暴く」を参照)

5.ログアウト機能はあるか、適切に実装されているか

「ログアウト機能がない、あるいはログアウト後「戻る」ボタンでセッションを再開できる場合」問題ありです。

「ログアウト機能」あります。

しかしログアウト後「戻る」ボタンをクリックすると

操作を再開することができました。

セッションが破棄されていません。

6.意図的に 10 回パスワードを間違える

「アカウントロックされない場合」問題ありです。

ログイン時にパスワードを10回以上間違えても「パスワードが違います」と出るだけで、アカウントロックはされませんでした。問題ありです。

その他(パスワードが6文字までしか登録されない)

admin(管理者)として会員一覧を見てみると、ID: wasbookのパスワードが wasbook ではなく wasboo と一文字少なく何かおかしいと感じます。

試しにユーザ test4:パスワード「password」で登録してみましたが「passwo」となりました。

どうやら表面上は8文字まで入力できるとなっていますが実際には6文字しか登録されていないようです。
またログイン時はパスワードの6文字目まで合っていれば7文字目以降が間違っていてもログインできます。

ソースコードを見てみると adduser.php にて mb_substr関数で先頭から6文字だけ取り出しています。PHP: mb_substr - Manual

<?php
$pwd   = mb_substr(filter_input(INPUT_POST, "pwd"), 0, 6);

DB上も varchar(6) と、格納できる最大文字数が6バイトとなっています。

MariaDB [todo]> show columns from users;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| id     | int(11)      | NO   |     | NULL    |       |
| userid | varchar(64)  | NO   |     | NULL    |       |
| pwd    | varchar(6)   | NO   |     | NULL    |       |

徳丸さんによると、このような実装は古いシステムでたまに見かけるという。昔はパスワードが6桁までというサイトが結構あり、表面上は7文字以上入力できても切り詰めてしまう仕様になっていることがある。
なお、入力できるパスワードの長さに決まったものはないが、現在では一般に「8文字以上」が最低ラインとされているという。
え? 同じIDで登録できる? コンビニ証明書で話題「同時処理」の危険性:“典型的やられサイト”で学ぶセキュリティのワナ(1/4 ページ) - ITmedia NEWS

前述のNIST Special Publication 800-63Bによると「(パスワードの)秘密の切り捨ては行ってはならない」とあります。

参考にした資料

www.slideshare.net

次回:やられアプリ BadTodo - 17.2 認証 対策 保存するパスワードのハッシュ化 - demandosigno

/* -----codeの行番号----- */