目次
始めに
Apacheのアクセス制限機能である「.htpasswd」ファイルに登録するパスワードのハッシュ化ツールをPHPの勉強も兼ねて作ってみた。
ハッシュ化パスワード作成
「.htpasswd」ファイルに記載するハッシュ化パスワードmd5(APR)とbcryptを作成。
表示されたパスワードを「.htpasswd」ファイルにコピー&ペーストする。
作成パスワード概要
md5 (APR) $apr1$ 接頭辞
MD5は、128ビット(16バイト)のハッシュ値を生成することができ、それは32桁の16進数の数によって特徴付けられる。md5(APR)はApache固有のアルゴリズム(37文字)
バージョン2.2.18以降ではデフォルトだが、近年では十分安全とは言えない。
互換性:Apache 全バージョン、Nginx 1.0.3以上
bcrypt $2y$ または $2a$ 接頭辞
blowfish暗号アルゴリズムを用いた、近年比較的安全であると考えられているハッシュ関数。
計算に多くの時間を要すが、これが安全である理由のひとつ。(60文字)
パラメータはストレッチ回数を設定。(数字が大きいほど複雑で安全だが、より生成が遅い)
※10以上の値を設定すると非常に重くなる。4〜17の範囲が指定可能だが,このツールはデフォルト値:05 (固定)
互換性:Apache 2.4以降(apr-util 1.5以上が必要)
bcryptで出力される文字列は全部がハッシュ値では無く、4つのパーツに分かれており毎回異なる値が出力される。検証するには専用の関数「Hash::check(‘平文’, bcrypt(‘平文’))」で、自動生成されたソルトとコストでハッシュ化した後に比較している。
パート1(1-3文字) = bcryptのバージョン($2y)
パート2(4-6文字) = コスト、ストレッチ回数(ハッシュ化演算の繰り返しの回数) ($04〜$17の範囲) デフォルト($05)
パート3(7-29文字) = ハッシュ化する度に生成されるソルト(乱数で自動生成) $から始まる23文字
パート4(30-60文字) = ハッシュ値 31文字
ツール説明
PHPのexecコマンドでWindowsベースのApacheコマンドhtpasswd.exeを呼び出し,入力したUSERIDとPASSWORDでハッシュ値を計算。作成したPHPファイルはブログルートに配置しiframeでWordPressに埋込(カスタムHTML)。PHP8環境なので前バージョンまでのコードで問題なかったものが,今回ワーニングとして表示されたりしたので,少し手こずった。
<?php
$id="";
$pass="";
$cost="5";
$err = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (!empty($_POST["id"]) && !empty($_POST["pass"])) {
$salt = $_POST["id"] . $_POST["pass"];
$id = $_POST["id"];
$pass = $_POST["pass"];
if(isset($_POST["cost"])) {
// セレクトボックスで選択された値を受け取る
$cost = $_POST["cost"];
}
$err = "";
$cmd = "htpasswd -b -n " . $id ." " . $pass;
$cmd1 = "htpasswd -B -C " . $cost ." -b -n " . $id ." " . $pass;
echo("md5(APR)");
echo '<br>';
exec($cmd,$opt);
foreach($opt as $value){
echo $value;
echo "\n";
}
echo '<br>';
echo '<br>';
echo("bcrypt");
echo '<br>';
exec($cmd1,$opt1);
foreach($opt1 as $value1){
echo $value1;
echo "\n";
}
} else {
$id = $_POST["id"];
$pass = $_POST["pass"];
$err = "input errors.";
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>htpasswd</title>
<meta name="robots" content="noindex, nofollow" />
</head>
<body>
<?php if (!isset($salt)) : ?>
<form action="" method="post">
<p>USERID <input type="text" name="id" value="<?php echo htmlspecialchars($id, ENT_QUOTES, "UTF-8"); ?>"></p>
<p>PASSWORD <input type="text" name="pass" value="<?php echo htmlspecialchars($pass, ENT_QUOTES, "UTF-8"); ?>"></p>
<p>COST <select name= "cost">
<option value = "4">4</option>
<option value = "5" selected>5</option>
<!-- <option value = "6">6</option>
<option value = "7">7</option>
<option value = "8">8</option>
<option value = "9">9</option>
<option value = "10">10</option>
<option value = "11">11</option>
<option value = "12">12</option>
<option value = "13">13</option>
<option value = "14">14</option>
<option value = "15">15</option>
<option value = "16">16</option>
<option value = "17">17</option> -->
</select></p>
<p style="color:red;"><?php echo $err; ?></p>
<p><input type="submit" value="submit"></p>
<p><a href="">return</a></p>
</form>
<?php else : ?>
<p>
USERID <?php echo htmlspecialchars($id, ENT_QUOTES, "UTF-8"); ?> <br>
PASSWORD <?php echo htmlspecialchars($pass, ENT_QUOTES, "UTF-8"); ?> <br>
COST <?php echo htmlspecialchars($cost, ENT_QUOTES, "UTF-8"); ?> <br>
</p>
<p><a href="">return</a></p>
<?php endif; ?>
</body>
</html>
動作環境作成
事前の環境設定
1.Apacheコマンドの「htpasswd.exe」はApacheインストールフォルダーのbinフォルダーにあるのだが,PHPから呼び出すのでPHPインストールフォルダーのルートフォルダーにコピーする。
2.今回作成のPHPファイルは,「passwdgen.php」の名前で,ブログのルートフォルダー(例:wordpress)にメモ帳でコピー&ペーストして保存する。
WordPressに埋込
カスタムHTML
WordPressの「投稿を編集」画面でカスタムHTMLを選択する。
「HTML を入力….」欄に下記コードをコピー&ペーストする。
<example.com>は該当のドメイン名に変更する。
<iframe src="https://<example.com>/wordpress/passwdgen.php" title="Passwords Generator" width="710" height="300">
</iframe>
貼り付け
これでとりあえず保存すれば,良いはず
まとめ
今回は連休中の空き時間に勉強を兼ねて遊びで作ったコードなので,最適化すべき箇所が多々あると思うがとりあえず動作しているので「よし!」としよう。
phpに加えてcss,javascriptを使用して見た目を良くすれば良いのだろうが,自分の為にハッシュ化パスワードを得る目的なのでこれで良いかな。
しかし,このパスワードハッシュ化関数は難解で理解しがたい面がある。(-_-;)汗
使用方法
「.htpasswd」ファイル
保存箇所はドキュメントルート以外の場所 例(d:/www/private_html/.htpasswd)
下記.htaccessファイルの4行目 AuthUserFileで指定
user:$2y$05$1qvc37CrMt87zIIdLtEsROVHvnd5w/axPXFOENHG5rsTLq4q609z6
「.htaccess」ファイル
サイト全体を制限する場合は保存箇所はWordPressのルート
例(d:/www/public_html/wordpress/.htaccess)
WordPressで既に自動作成されているので,冒頭に追加する。(下記1~6行目)
# BASIC認証
AuthType Basic
AuthName "Please enter your ID and password"
AuthUserFile d:/www/private_html/.htpasswd
AuthGroupFile /dev/null
require valid-user
# リダイレクト設定
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/wordpress/wp-cron.php$
RewriteBase /
# http又はwww有りの場合、https://hoge.com/blog/にリダイレクト
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^(.*)$ https://hoge.com/wordpress/$1 [R=301,L]
</IfModule>
# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /wordpress/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wordpress/index.php [L]
</IfModule>
# END WordPress
管理者用画面のみをBASIC認証保護する場合は,上記の1~6行を次の内容に置き換える。
通常のWordPressログイン画面の前にBasic認証画面で認証する。
【注意】投稿記事にWordpressの機能であるパスワード保護を設定すると,wp-login.phpにアクセスするのでBASIC認証が必要となる。ので記事にパスワード保護は使えない。
# BASIC認証
<Files wp-login.php>
AuthType Basic
AuthName "Please enter your ID and password"
AuthUserFile d:/www/private_html/.htpasswd
AuthGroupFile /dev/null
require valid-user
</Files>