パスワードのフォーマットを選択可能に(LDAP互換に)

  • 元タイトル: ユーザー定義のパスワードをmd5hashに
  • ページ: BugTrack
  • 投稿者: merlin
  • 優先順位: 普通
  • 状態: 完了
  • カテゴリー: 本体新機能
  • 投稿日: 2004-09-30 (木) 17:31:54
  • バージョン: 1.4.6

修正

(PukiWiki>1.4.6)

管理者パスワードとユーザーパスワードの保存形式を、「RFC2307および既存のLDAP実装」に準拠させました。その結果、管理者が保存方式を自由に選択(変更)できる様になりました。具体的にはMD5以外に平文、SHA-1、Unix crypt()、OpenLDAPが利用できるパスワードフォーマット全てを利用できる様になりました。

従来のMD5パスワード保存形式を使う場合は、先頭に

{x-php-md5}

を追加する必要があります。

使用できるフォーマット

保存フォーマット / scheme prefixアルゴリズムソルト(seed)
1Cleartext (平文)なし / {CLEARTEXT}無変換なし
2LDAP SSHA (sha-1 with a seed){SSHA}SHA-1あり
3LDAP SHA{SHA}SHA-1なし
4LDAP SMD5 (md5 with a seed){SMD5}MD5あり
5LDAP MD5{MD5}MD5なし
6LDAP CRYPT{CRYPT}システム依存あり
7PHP sha1()関数の出力{x-php-sha1}SHA-1なし
8PHP md5()関数の出力{x-php-md5}MD5なし
9PHP crypt()関数の出力{x-php-crypt}システム依存あり
 
  • ※今後推奨する方式は、SHA-1アルゴリズムが利用できる環境ならば SSHA、利用できないならば SMD5です。ソルトを用いる事ができるこれらの形式は、設定ファイルの「覗き見」に対してより高い耐性を持っています。
  • ※ソルトを指定/変更できる保存方式は、「例え実際のパスワードが(偶然または意図して)同じであっても」パスワードの保存文字列を異なる値にスクランブルする事が可能であるため、「クラックに成功した特定のパスワードと、同じパスワードを利用している別のユーザーを探索する」行為を困難にします。(アカウントごとに異なるソルトを与える事で実現可能になります)
  • ※LDAP SHAと PHP-sha1()、LDAP MD5 と PHP-md5()はフォーマットが少し異なるだけで内容は同一です。LDAP CRYPT と PHP-crypt() の内容は同一です。
  • ※SHA-1アルゴリズムは PHP 4.3.0 以降、あるいは 'mhash' エクステンションが組み込まれた環境でなければ利用できません。したがって該当する環境でなければ、このアルゴリズムを用いるパスワード保存方式を利用することはできません。
  • ※cryptの出力はUnixシステムのパスワードやApache Webサーバーが用いる .htpasswd などのパスワード保存方式と同じであり、基本的に互換性があります。しかしcryptが出力する内容はシステム依存(実装依存)です。他のシステムへ / 他のシステムから設定を持ち越した場合や、異なる実装では動作しない(異なる結果が出力された結果、認証が通らない)可能性があります。
     古いcryptの出力例:     saal5GtBC.fJc
     新しい方式の出力例(*): $1$salt$X09lt99YPMcdxvr9cmDjS0
         (* 内部でMD5を使用)

使用例

 // SELECT ONE
 //$adminpass = 'pass';            // Cleartext
 //$adminpass = '{CLEARTEXT}pass'; // Cleartext
 //$adminpass = '{SSHA}B78f8i/RpNC+CyFdKLH2odaK8hlPNjlOOUUyMA=='; // SSHA 'pass'
 //$adminpass = '{SHA}nU4eI71bcnBGqeO0t9tXvY1u5oQ=';              // SHA 'pass'
 //$adminpass = '{SMD5}o7lTdtHFJDqxFOVX09C8QnlmYmZnd2Qx';         // SMD5 'pass'
 //$adminpass = '{MD5}Gh3JHJBzJcaScd3wyUS8cg==';                  // MD5 'pass'
 //$adminpass = '{CRYPT}$1$nxrVut5a$c9LdXN1rKQC1HQOwBY4O//';      // CRYPT 'pass'
 //$adminpass = '{x-php-sha1}9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684'; // sha1('pass')
 //$adminpass = '{x-php-md5}1a1dc91c907325c69271ddf0c944bc72';          // md5('pass')
 //$adminpass = '{x-php-crypt}$1$nxrVut5a$c9LdXN1rKQC1HQOwBY4O//';      // crypt('pass')

cvs-raw:UPDATING.txt.diff?r1=1.23&r2=1.24&diff_format=u に注意点を書いた通りですが、既存の管理者パスワード(MD5ハッシュ)を今後も使用する場合、先頭に '{x-php-md5}' というフォーマット宣言を付ける必要があります。

平文を除く八種類の保存フォーマットについては、強化されたmd5プラグインで生成・検証することができます。

参考文献など

メッセージ

編集や閲覧認証に使われるユーザー定義のパスワードが直打ちなので md5hashにした方がいいのではないでしょうか?
PukiWiki/1.4/ちょっと便利に/任意のページごとの閲覧・編集制限 参照

auth.php

	// ユーザリストに含まれるいずれかのユーザと認証されればOK
	if (!isset($_SERVER['PHP_AUTH_USER'])
		or !in_array($_SERVER['PHP_AUTH_USER'],$user_list)
		or !array_key_exists($_SERVER['PHP_AUTH_USER'],$auth_users)
-		or $auth_users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW'])
+		or $auth_users[$_SERVER['PHP_AUTH_USER']] != md5($_SERVER['PHP_AUTH_PW']))
	{

pukiwiki.ini.php

/////////////////////////////////////////////////
// ユーザ定義
$auth_users = array(
-'foo' => 'foo_passwd',
-'bar' => 'bar_passwd',
-'hoge' => 'hoge_passwd',
+// ユーザ名 => パスワード(md5 hash)
+// pukiwiki.php?md5=pass のようにURLに入力し
+// MD5ハッシュにしてから記入してください。
+// 面倒ならば以下のようにどうぞ
+// ユーザ名 => md5(パスワード)
+'foo' => 'f122914144e12fa7d7b7b14cc223f671',
+'bar' => 'f53ae779077e987718cc285b14dfbe86',
+'hoge' => md5("hoge_passwd"),
);

  • md5("パスワード")と計算するのではなく、md5("パスワード"."ユーザ名")としないと同じパスワードは同じmd5出力列になります。たとえばfooさんが"mypassword"で、barさんが"mypassword"だったとき、fooさんのパスワードがわかれば自動的にbarさんのパスワードがわかってしまいます。このような混ぜ物(Salt)があるとより安全です -- すずきひろのぶ? 2004-10-18 (月) 11:55:15
  • コメントありがとうございます :) 検証する側で同じパターンで文字連結してからmd5を取れば問題ないですね。 -- henoheno 2004-10-18 (月) 21:35:42
  • ロジックの根本対応せずとも、md5 対応程度はコミットしておいても良いのでは? -- upk 2005-02-19 (土) 19:26:09
    • お疲れ様です。とり急ぎ明日 1.4.5_1 をリリースする予定なので、それ以後になりますです -- henoheno 2005-02-19 (土) 20:56:26
  • もはや1.3と1.4の関係は、1.4.5では無いということですかね。では、この状況をどう料理しておきましょうかね? -- upk 2005-02-20 (日) 00:46:34
    • こんにちは。「1.3と1.4の関係」という部分をもう少し説明してください (^^; それとこのトピックを取り上げるにあたり、何か背景となる話題をすっ飛ばしていませんか? -- henoheno 2005-02-20 (日) 17:14:22
    • (これ以後のリリースサイクルに関する話題はBugTrack2/12へ移動しました)
  • 私が聞きたい背景情報というのは(移動しましたが)そういう話ではありません。「PukiWiki Plus! とかで一部この機能に依存しているところがある*1からこれを先に片付ければ楽になるのか、なるほど~」とか「すずきひろのぶさん?が言われているSaltのことを考慮するとmd5($_SERVER['PHP_AUTH_PW'])という部分は md5($salt . $_SERVER['PHP_AUTH_PW']) なんて風になっていないと駄目なので、そこまでケアしていない様ではこのBugTrackが「CVS待ち」の状態だとは思えない」とかそういう反応をしたいので、率直にこのBugTrackをピックアップされた背景を語っていただきたかったという事です (^^; -- henoheno 2005-02-24 (木) 23:30:30
  • やっと素晴らしい言い訳がみつかったわけですね。 -- 2005-03-02 (水) 00:47:39
    • 先頭のすずきひろのぶ?さんのコメントと、upkさんのコメントをきっかけに動き出している下の話に目を通されていますか? 「言い訳」というのは上に挙げた二つの話題のどちらで、素晴らしいのはどちらですか? 短く鋭く愛を込めたツッコミをお願いします。 -- henoheno 2005-03-02 (水) 22:46:43

パスワードのマルチフォーマット対応

ちょっと確認: LDAP, LDIF(LDAP Data Interchange Format), slappasswd

  • OpenLDAP Faq-O-Matic: What are {MD5} and {SMD5} passwords and how do I generate them?
  • OpenLDAP Faq-O-Matic: What are {SHA} and {SSHA} passwords and how do I generate them?

ちょっと確認: cryptなどのハッシュ関数


  • ldiffライクに「+'bar' => '{md5}f53ae779077e987718cc285b14dfbe86',」とかはだめすかね? 殆どの場合問題ないと思うのですが -- ELF 2005-02-23 (水) 23:14:40
    • すいませんldiffライクというのがわかりませんでしたが、すずきひろのぶ?さんが言われているのは pukiwiki.ini.php の中身が(例えば脆弱性のある別のCGIを経由したりして)外部に漏洩した時の事を言われているので、md5ハッシュの部分がどこからどこまでかを特定できるようでは意味がないのです。md5()関数に与える文字列を、md5()に与える前に加工することで、MD5ハッシュをスクランブルするのがキモなのです。当然ながらSaltの値の一部は個々のPukiWiki管理者が任意に決定できる(= ユーザー名とパスワードの組み合わせがたとえ同じ文字列であっても、PukiWikiごとにハッシュが異なる状態にできる)ものが好ましいです。Googleに問い合わせればバレるようなハッシュを作らないようにするという点では、PukiWiki独自のsaltがsaltの一部に加えられているとなお好ましいです -- henoheno 2005-02-24 (木) 23:25:52
 $string_example  = 'pkwk ' .    // Hope PukiWiki-original hash
                  $admin_defined_salt . ' ' . // Site-admin original pass-phrase
                  $username . ' ' . // Username
                  $password;  // Something password
 $hash = md5($string_example);
  • ただ、あんまり複雑にしすぎると管理者さんによるハッシュ生成の手間がかかるというトレードオフがあります。 -- henoheno 2005-02-24 (木) 23:45:24
  • 上記の例であれば、管理者は "pkwk admin_pass username password" といった一本のパスフレーズをMD5にかけることでハッシュを取り出すことになります。 -- henoheno 2005-02-24 (木) 23:46:51
    • このように、PukiWikiユニークかつ、個別のPukiWikiユニークかつ、ユーザーネームごとに、パスワードが違うたびに異なる文字列を用意することで、生成されるハッシュがユニークな値となることがより期待できるようになります。 -- henoheno 2005-02-24 (木) 23:51:09
  • 少々考えましたが、PukiWiki管理者がPukiWikiごとのSaltをきちんと考えてくれる状況であれば 'pkwk' という固定文字列は不要で、インストール直後の状況であれば 'pkwk' という文字列は推測できるので不要ですね。(結論: あっても無くても同じ => 不要) -- henoheno 2005-02-25 (金) 23:37:00
    • $adminpass と絡めるとか (^^; -- teanan 2005-02-26 (土) 02:57:07
      • そうすると・・・Unixのrootユーザーのパスワードに相当する $adminpass を変更した途端に、他のユーザーがログインできなくなるような依存関係が生じてしまうでしょう ;) -- henoheno 2005-02-26 (土) 11:57:08
      • ぬお、確かに・・・orz -- teanan 2005-02-26 (土) 19:05:09
    • UNIXのshadowなどは「$1$」+ハッシュ生成時に作成した5文字くらいのランダムなsalt+md5パスワードになります.saltが推測できてしまいますが,ある程度の強度はあると思います. -- ELF 2005-02-26 (土) 08:12:19
    • ldiff likeといったのはパスワード欄を「{暗号化方式}ハッシュ」にしませんかということです.単にmd5('passwd')なり何らかの結果のみにすると後々の拡張がしづらいということで,よくあるぱたーんです. -- ELF 2005-02-26 (土) 08:13:39
  • Linux Shadow Password HOWTO: shadow パスワードを使うべき理由
    • http://www.linux.or.jp/JF/JFdocs/Shadow-Password-HOWTO-2.html
    • "ユーザがあるパスワードを決めた場合、このパスワードはランダムに決められた salt と呼ばれる値を用いてエンコードされます。こうすることで一つの文字列がエンコードされた結果として取りうる結果は 4096 通りになります。salt の値はエンコードされたパスワードと一緒に記録されます。"
    • "クラッカーはこのような事情をよく知っているので 4096 個全ての salt を用いて辞書の単語とよく使われそうなパスワードをあらかじめエンコードしておきます。そして、/etc/passwd に書かれているエンコードしたパスワードをこの結果と比較します。ここで一致するものが見つかれば、クラッカーは他人のパスワードを破ったことになるわけです。これは「辞書攻撃」と呼ばれるもので、正規の認証を受けずにシステムにアクセスするための常套手段です。"
  • ELFさんコメントありがとうございます。ひとつは一方向ハッシュが生成される組み合わせを拡大しようというsaltですね。もう一つのお話は例えばMD5からSHA-1*2に切り替えるられるようにしようということで、まず設定文字列の先頭を見て方式を調べ、その方式でハッシュを生成し、方式と連結した文字列と比較するというイメージでしょうか。 -- henoheno 2005-02-26 (土) 12:04:54
    • 前者のsaltについては、PukiWikiの場合ハッシュの生成および設定が基本的に人力であるため、「ハッシュ生成時に作成した5文字くらいのランダムなsaltを取り出す」ような方式を強いるのが難しい(いちいち頭を使わねばならない)と思っています。md5を計算するプラグイン自体は既存で、これをカスタマイズすれば、やや難しいハッシュ生成を自動化できないこともありませんが、md5プラグイン自体がそもそもネットワークにデータを平文で流してしまう矛盾した特性を抱えているため、利用手段としてうまくないと思います。 -- henoheno 2005-02-26 (土) 12:07:37
    • 前者はsaltな話がでてたので*3,UNIXではこうなってますよという紹介.次はまぁそんなところです > ldifライクでの切り替え -- ELF 2005-02-27 (日) 07:12:40
  • メモ: PukiWiki毎のsaltを管理者が別個に設定したとして、両方の設定ファイルが漏洩したとする。このとき、それぞれのPukiWiki用saltも漏洩しているはずなので、それぞれに対する辞書攻撃は依然として可能。また、一方のあるユーザーで辞書攻撃が成功したとき、他方のPukiWikiに同じユーザーが存在した場合、そのユーザーが全く同じパスワードを使っていると仮定できるため、別のPukiWikiのsaltを使ったテストを最初に行うことができる。 = PukiWiki毎のsaltはあんまり意味がないか、労力と見合わないかも -- henoheno 2005-02-26 (土) 12:15:47
 switch ($method) {
 case 'md5':  $hash  = $method . ':' . md5($username . $password); break;
 case 'sha1': $hash  = $method . ':' . sha1($username . $password); break;
 default: die_message('Unknown method'); break;
 }
  • これまでのご意見を整理するとこんな感じですか :) -- henoheno 2005-02-26 (土) 12:25:26
  • メモ: メモリ中のハッシュ文字列自体をそもそも改変する攻撃のことも考えてみては -> 自分。 (今のこの話題とは関係ない) -- henoheno 2005-02-26 (土) 12:32:42
  • 1.4.5_1も出せたし、ELFさんからの確認も取れたので、この方向でテスト実装ができそうですね -- henoheno 2005-02-27 (日) 12:28:39
    • あーこんな感じ.面倒じゃなかったら「{method}」が長いものに巻かれろ的でステキです. -- ELF 2005-02-28 (月) 22:55:07
    • 長いモノに巻かれろと仰るなら、巻くべき長いモノについて明確にして大文字小文字まで一致させるようにしたいのですが、ldiffについてはどこを見ると良いでしょうか。とりあえずopenldapだとMD5の字が大文字だったり、MD5のハッシュの表現形式がPHPのmd5()関数の出力と異なっていたりして、キッチリ巻けそうに見えないのですが (^^; -- henoheno 2005-03-02 (水) 22:49:13
  • ちゃんと調べずに書いていました.すみません.確かに生成されるハッシュ値が違いますね.一応ここに定義されているようですが,生成方法にたどり着くほど読みきれませんでした*4.少なくともPHPのmd5()と値が違うということで混乱を避けるためにhenohenoさん提示の方式でいいと思います. -- ELF 2005-03-04 (金) 16:12:36
  • ldiff → ldif(LDAP Data Interchange Format)ですかね。 -- 2005-03-04 (金) 17:47:44
  • slappasswdで試してみました。
    # slappasswd -h '{MD5}' -s piyo
    {MD5}B+GuIasPRiqZzXK0Pi6AVg==
    ぱっと見BASE64エンコードのようなので、PHPでmd5(バイナリ)をbase64エンコードしてみたら
    # php
    <?php echo '{MD5}' . base64_encode(md5('piyo', TRUE)) . "\n"; ?>
    {MD5}B+GuIasPRiqZzXK0Pi6AVg==
    同じ値が出せましたよ。 -- 2005-03-04 (金) 17:47:44
  • sha1実装(PHP4.3.0以前用)はここにコードがありますね。
  • saltつき (SMD5, SSHA, ...)はここのコードが参考になるかと。
  • ということで。teanan:自作プラグイン/crypt.inc.php -- teanan 2005-03-04 (金) 18:50:08
  • 皆さんツッコミありがとうございます。やっと解りました。筋が悪くてすいません (^^;*5 PukiWikiのパスワードシステムのフォーマットについて、LDAP互換のフォーマットにも対応させておくと、少々興味深い事になりそうですね。その一方で、今のPukiWikiユーザーになじみのあるPHP md5()関数の表現形式は今後も維持する必要があります。またPHP sha1()関数の表現形式が扱えても良いでしょう。 -- henoheno 2005-03-08 (火) 23:38:24
    • ということで、PHP md5() か PHP sha1() か 平文か、というレベルではなく、OpenLDAPとの互換性を含めたマルチフォーマット対応という路線に視野を広げて検討を進めたいと思います。 -- henoheno 2005-03-08 (火) 23:38:49
    • といってもRFC2307の該当箇所をさらっと見た限り {crypt}(Unixの標準), {md5}, {sha}(アルゴリズムとしてはSHA-1), slappasswd のマニュアルにある {smd5}, {ssha}, そしてPukiWikiが従来利用しているPHP md5()関数の表現形式として {x-php-md5}*6, 同じくsha1の表現形式として {x-php-sha1} 、そして平文({cleartext}あるいは{clear}あるいは識別符号なし)の8つについて考えれば良さそうですね :) 面白くなりそうだ -- henoheno 2005-03-08 (火) 23:45:25
    • LDAPに関する基礎知識とか、標準的なRFCやその日本語訳については osdev-j:LDAP をどうぞ。RFC関連はたったいまアップデートをかけました。 -- henoheno 2005-03-08 (火) 23:49:08
  • とりあえずmd5プラグインへの妙なこだわりを一部捨てて、これを拡張して PHP md5(), PHP sha1(), PHP crypt(), OpenLDAP形式 MD5, OpenLDAP形式 SHA を出力できるようにしてみました。 {MD5} のようなスキームプレフィックスも追加できます(選択式)。中にある plugin_md5_compute() 関数をいずれ lib/func.php あたりに持っていくイメージでいます。PukiWikiをlocalhostで使うぶんには、これはこれで便利かもしれない :) -- henoheno 2005-03-28 (月) 23:23:54
    • cvs:plugin/md5.inc.php (1.8)
    • どうしてslappasswdが表示するスキームプレフィックスが大文字なのかは、いまいちわからず。 -- henoheno 2005-03-28 (月) 23:26:06
  • ご紹介いただきました、PHPマニュアル中のノートにある SSHA のコードをチェックしました*7。このサンプルコードは PHP mhash extension を必要とするmhash関数を利用して PHP sha1() と同等の処理を行っている様です。この内容からは SSHA の構造(saltがどこか、といった)の推測ができるようですね。 -- henoheno 2005-03-31 (木) 00:25:21
  • SSHA & SMD5 対応から始まって、一気に管理者パスワードとBasic認証のユーザーパスワードの複数フォーマット対応まで片付いてしまいました (^^; (展開はや) -- henoheno 2005-04-05 (火) 22:34:42
    • 互換性情報については cvs:UPDATING.txt (1.24) をご覧下さい。
    • sha1() のケアについては、mhashエクステンションが存在した場合にそれを利用する互換コードを用意するに留めさせていただきました。各種情報をお寄せいただき、ありがとうございました :) -- henoheno 2005-04-05 (火) 22:57:44
    • md5('user' . 'passwd') の類はどうするかは考えましたが、管理上の面倒臭さがより強まってしまうのと、少なくともこれでSMD5(salt付きMD5)が使える様になりましたので保留とさせて下さい。 -- henoheno 2005-04-05 (火) 23:02:09
    • 現状、SMD5およびSSHA を新たに生成する場合のsaltのランダムさは crypt() に依存しています (コード参照 (^^; ) 心配な方は (md5プラグインなどで生成する際に)任意のsaltを叩き込んで下さい。 -- henoheno 2005-04-05 (火) 23:25:41
    • パスワードを生成する関数 pkwk_hash_compute() はコマンドラインツールから利用される事も想定して作ってありますので、php cli が使える環境であれば auth.php (あとfunc.php)をrequire() することでコマンドラインから利用することもできると思います。 -- henoheno 2005-04-05 (火) 23:48:19
  • 保存しているパスワードを検証する際に、スキーム(フォーマット)の大文字・小文字を保存せずに比較するため、仮に {X-PHP-MD5} などと入力した場合に({x-php-md5}という値が返る為)検証時にパスワードが一致しない状態になっていました。そこで pkwk_hash_compute() のデフォルト動作として、入力されたスキームの文字列をそのまま用いる様に修正しました。 -- henoheno 2005-04-10 (日) 12:37:55
  • 一通り片付きましたので、状態を「完了」とします。また何かあれば書き込んで下さい :) -- henoheno 2005-04-11 (月) 22:33:21
    • なお、「スキームプレフィックスが無かった時のデフォルト」は空文({CLEARTEXT}、保存フォーマットなし)です。いずれ空文の使用を禁止しても良いとも思うのですが、今禁止してしまうと過去のユーザーパスワードとの互換が無くなりますので行い(え)ません。 -- henoheno 2005-04-11 (月) 22:41:03
  • $adminpassに {CLEARTEXT} が使用できなかった点を修正しました。そのほかクリンナップ。 -- henoheno 2005-06-04 (土) 11:17:24
  • より関数として自然な形となる様に、 pkwk_hash_compute() の第一引数と第二引数を入れ替えました。結果的にcrypt()関数と引数の意味と順番が揃いました -- henoheno 2005-06-13 (月) 23:13:04

*1 あくまで例として適当なことを言っています
*2 どっちも危なくなってきているらしい
*3 実は最初の書き込みでは気づいてなかった
*4 ここにたどり着くのに精一杯
*5 ldiff というコマンドラインツール?についてGoogleに質問した瞬間から迷走が決まっていたのかも・・・
*6 RFC2307には「その他のスキームを定義するんなら x- を付けとけ」と書いてある気がする
*7 前提として、私はPHPマニュアルにユーザーが追記したノートが、特にコメントがなければPHP Documentation Groupの資産となることを知っています(これはノートを追記しようとすると出てくる文書に明記されています)

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-09-19 (土) 19:03:46
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u8. HTML convert time: 0.341 sec.

OSDN