ウェブアプリにおけるパスワード管理を考える

今更感溢れますが、あらためてパスワード管理について考えてみようと思います。

外部からの攻撃によるパスワードの漏洩

想定できるパターンとしては、主に2つ。

  1. キーロガー、ショルダーハックによる漏洩。
  2. SQLインジェクション等によるデータの漏洩。

1.に関しては、被疑者にならない為に、人のパスワードを安易に見ない・覚えない・知らないふりが求められます。僕は通称「あいっちむいてホイ」と言ってます。
また、仮に見られても覚えられにくいパスワードにする事も、この点に挙げられます。

対策として、キーロガーを稼働させるようなマネをしない事もありますが、TrendMicro パスワードマネージャーといったパスワード管理ツールを使う、周りに人が居たら「あっちむいてホイ」と一言かける、などあります。

  1. については、サーバサイドの実装の不具合、もしくはデータの取扱いの不備が挙げられます。
    例えば、「MD5アルゴリズムでハッシュ化したパスワードが、SQLインジェクションにより漏れた。」「アカウントのDBをCSV化した際、扱いがまずかった」等が考えられます。

攻撃者は、ID, Password(Hash)を手に入れた時、以下のような処理を行います。
例えば、以下のような形式のパスワードリストを想定します。

user00, 1f231e8ea1d9f05efc8fe29168e547da
user01, e3bc38a4faa625d074664d572d810c1e
user02, 13037dd20cd291e694cdf19b5a913f5e
user03, 5b19dee88befc864879bd30c28999552
user04, bd323337d92d8a09b9a5d3c5a19e51cd
user05, 6d3693417bea41634cd187708c011c9a
user06, 1d277e71e1b0b9b798e8536475cd04de
user07, bd323337d92d8a09b9a5d3c5a19e51cd
user08, 953c3993b756e2689f4a31a6329554e1
user09, 6087ae29e30766a80dc3e3f8fed10353
user10, bd323337d92d8a09b9a5d3c5a19e51cd
user11, bd323337d92d8a09b9a5d3c5a19e51cd
user12, 953c3993b756e2689f4a31a6329554e1
user13, bd323337d92d8a09b9a5d3c5a19e51cd
user14, 953c3993b756e2689f4a31a6329554e1
user15, 80ef41acf15e903e8c186945054053fd
user16, 953c3993b756e2689f4a31a6329554e1
user17, bd323337d92d8a09b9a5d3c5a19e51cd
user18, 953c3993b756e2689f4a31a6329554e1
user19, bd323337d92d8a09b9a5d3c5a19e51cd
user20, 953c3993b756e2689f4a31a6329554e1

ここから、アタックする為のディクショナリを抽出します。

$ cat test.passwd | awk -F"," '{print $1}' > user.dic
$ cat user.dic
user00
user01
user02
(以下略)
 
$ cat test.passwd | awk -F", " '{print $2}' | sort -u > hash.dic
 
$ cat test.passwd | awk -F", " '{print $2}' | sort | uniq -c | sort -r
   7 bd323337d92d8a09b9a5d3c5a19e51cd
   6 953c3993b756e2689f4a31a6329554e1
   1 e3bc38a4faa625d074664d572d810c1e
(以下略)

以上により、2つのパスワードが複数ユーザで使いまわされている事が確認できます。

では、これらのハッシュ値をMD5と期待して、8文字の半角英数・数字で成るパスワードを解析するコードを実装します。
サンプルコードなので、コマンドの絶対パスの指定等は割愛します。
このコードの実行結果の事を、通称レインボーテーブルと言い、一般的に公開されているものでは数TBに上ります。が、最近のクラウド事情の進化で、安価に利用する事ができるようになってきました。
尚、このコードは少し改造する事でマルチスレッド化が可能ですが、悪用はご遠慮くださいませ。

#!/bin/sh
 
KEY="a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0"
CMD_MD5='md5'
 
for i0 in ${KEY}
do
 for i1 in ${KEY}
 do
  for i2 in ${KEY}
  do
   for i3 in ${KEY}
   do
    for i4 in ${KEY}
    do
     for i5 in ${KEY}
     do
      for i6 in ${KEY}
      do
       for i7 in ${KEY}
       do
        PASSWD=`echo "${i0}${i1}${i2}${i3}${i4}${i5}${i6}${i7}"`
        HASH=`echo ${PASSWD} | ${CMD_MD5}`
        echo "${PASSWD}, ${HASH}"
       done
      done
     done
    done
   done
  done
 done
done
 
exit 0

アプリケーション実装上におけるパスワードの取扱い

現実問題として、エンドユーザにどこまでパスワード変更を強要するか、というトレードオフになりますが、ここでは一般的にありがちな「パスワード変更なし」を前提として、サーバサイドとアプリケーションによるアプローチでどこまで防ぐ事ができるか検討します。

ユーザのパスワードを含む部分は、主に以下の通りです。

  1. 認証データベースのテーブル内(リードレプリカ含む)
  2. データベースのバックアップファイル(SQLファイル生文)
  3. 認証中のWebサーバのメモリ内

ここでは、攻撃がやりやすい2, 3について記述します。

データベースのバックアップファイル

SQLサーバの定期的なダンプは、運用上欠かすことが出来ない行事であり、鉄板と言われる運用タスクです。
しかし、ここで注意しなければいけない事は、DB内の全てのデータを生文で取り扱う事であり、より一層の気遣いを必要とします。

例えば、以下のような対策が考えられます。

  • ファイルはHTTPといったプロトコルではなく、SSH/SCPでのみ転送するようにする。
  • バックアップ専用サーバを用いて、Apache等が稼働していない状態で保管する。
  • PGP等で暗号化する。
  • オブジェクトストレージを使用する場合、適切な権限管理を行う。
認証中のWebサーバのメモリ内

認証を行う際、Webサーバには『ユーザが入力したパスワード』がメモリ内に保持されています。
例えばPHPの場合、セッション毎にPHPのプロセスが独立する形になる為、共有メモリにアクセスしてもこれらを得ることは出来ませんが、アプリケーションのデバッグログといった形で入力値を保存してしまう場合があります。
開発にフレームワークを使用していると、デバッグログが出力可能な場合があります。このデバッグログにGET/POSTの入力値が含まれ、及びそれが流出した場合、攻撃の対象となりうる可能性があります。
同様に、認証の高速化を目的としてKVSにクレデンシャルを保存していた場合、何らかのファクターの次に、高速なアタックが可能になる可能性があります。

既存アルゴリズムとソルトを使ったハッシュの難読化

さて、ここ数年でOSS LAMP CMSを観ていて対策が進んでいるので、少しご紹介しますが、既存のハッシュアルゴリズムやソルトを組み合わせる事により、独自のハッシュアルゴリズムを作り出す事が可能です。

例えば、「ID:muses」「PW:LOVELESSWORLD」を例として、サイト独自のソルトを使わずに独自のハッシュアルゴリズムを簡単に生成してみます。

#!/bin/sh
 
ID="muses"
PW="LOVELESSWORD"
 
HASH1=`echo ${PW} | shasum | awk -F" " '{print $1}'`
HASH2=`echo ${ID}_${HASH1}_${ID}` | shasum | awk -F" " '{print $1}'
 
echo $HASH2
exit

以上により、SHA1とECHOしか使っていませんが、二重にハッシュを生成する事で攻撃者が解読しにくいハッシュを作る事ができました。
攻撃者はHASH2をレインボーテーブルで解読しようとしますが、PWをハッシュ化した上でIDをソルトとして使用する為、この例では53文字の文字列を解析しなければいけません。
仮に解析が出来たとして、今度はHASH1が二重にハッシュ化されている為、解析は二度手間となります。
これにより、仮にハッシュが漏洩した場合でも、単純な1PASSの解析で終わらない為、攻撃者は攻撃を諦めることになるでしょう。

おわりに

先日も書きましたが、セキュリティの基本は「攻撃を面倒にする」です。
某初春とお姉さまが戦った時には、「サーバの蓋を開けて水ぶっかけた方がマシ」という程の荒々しい闘いだったそうですが(笑)、そもそもお姉さまの処理能力高いっす…。

元記事はこちら

あらためてウェブアプリのパスワード管理を考える