Nginx で扱えるセキュアなリンクを作成する
あくまで、Nginx では、URLのアドレスおよび URLパラメータ 情報から認証を行うだけです。
実際のURLアドレスおよび URLパラメータ は、phpスクリプトなどの外部の動的なページなどで作成する必要があります。
ここでは、phpを用いて動的なページで 一時的なセキュアなリンク を作成してみます。
以下は、例として http://exmaple.com/securelink.php でアクセスできる securelink.php ファイルとします。
また、http://exmaple.com/secure/ へのアクセスは、セキュアなリンクからのみを許容し、以外をすべて403を返信するものとします。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test SecureLink</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<?php
// 秘密鍵 になります。なんでもOKですので、ここでは日本語(UTF-8)で設定してみます。
$secret = '日本語でもOK?';
// セキュアなリンク からでないとアクセスできないURIを設定します。
$path = '/secure/';
// 公開鍵として、有効期限を time() + 秒 で設定します。
// -- この有効期限の設定の仕方は、Nginxではこの方法でしか認識できません。
$timestamp = time() + 3600; // 60(秒) x 60(分) = 3600(秒) = 1(時)
// "秘密鍵 + パス + 公開鍵" を Nginxで扱うことができる md5 で暗号化します。
$hash = base64_encode(md5($secret . $path . $timestamp, true));
// +,/,= は、URLパラメータとして扱えないので、置換します。
$hash = strtr($hash, '+/', '-_');
$hash = str_replace('=', '', $hash);
// セキュアなリンクを出力します。
$url = "{$path}?s={$hash}&t={$timestamp}";
echo '<a href="'.$url.'">シークレットリンク</a>';
?>
</body>
</html>
|
ここでの例では、http://exmaple.com/securelink.php へアクセスすると以下のようなシンプルなリンクだけのページが表示されるはずです。
<a href="/secure/?s=9TYDMnkdAZ_9VM3OQjMGjQ&t=1369388653">シークレットリンク</a>
|
上記のようなリンクを出力します。
次に、ここでの例では、http://exmaple.com/secure/ へアクセスした際に、認証OKの場合に出力されるべきページを準備しておきます。
以下の例は、ファイル名省略なので、http://exmaple.com/secure/index.html でアクセス可能な index.html ファイルとします。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test SecureLink</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<h1>おめでとうございます。</h1>
<p>おめでとうございます。<br />
あなたは、見事にこのページを見ることができました。
</p>
</body>
</html>
|
このページが表示されれば、以下のような文言のページが表示されるはずです。
Nginx で一時的なセキュアなリンクを使ってみる(secure_link,secure_link_md5ディレクティブを使ってみる) との違いは、ここからで、
一時的なセキュアなリンクの整合性(認証)をチェックphpスクリプトを作成します。
以下は、例として http://exmaple.com/secure/authcode.php でアクセスできる authcode.php ファイルとします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| <?php
// 秘密鍵 になります。なんでもOKですので、ここでは日本語(UTF-8)で設定してみます。
// -- リンク生成時と同じ秘密鍵 を設定します。
$secret = '日本語でもOK?';
// セキュアなリンク からでないとアクセスできないURIを設定します。
// -- ここではアクセスされたURIそのものになります。
$path = $_SERVER['REQUEST_URI'];
if(($arg_pos=strpos($path,'?'))!==false){
$path = substr($path,0,$arg_pos);
}
// 公開鍵として、有効期限を URLパラメータから抽出します。
$timestamp = $_GET['t'];
// URLパラメータの md5 で暗号化された情報を抽出します。
$hash_arg = $_GET['s'];
// "秘密鍵 + パス + 公開鍵" を md5 で暗号化します。
$hash = base64_encode(md5($secret . $path . $timestamp, true));
// +,/,= は、URLパラメータとして扱えないので、置換します。
$hash = strtr($hash, '+/', '-_');
$hash = str_replace('=', '', $hash);
// ここで作成したMD5暗号情報とURLパラメータのMD5暗号情報が一致するか?
// 有効期限ないか?
if($hash_arg == $hash && $timestamp >= time()) {
// いずれもOKなら、成功時のページを読み込みます。
include 'index.html';
} else {
// 失敗時は、403を返信します。
header("HTTP/1.0 403 Forbidden");
}
?>
|
基本的に、一時的なセキュアなリンク を作成する手順と同じようにMD5暗号化情報を作成し、
URLパラメータで引き渡された MD5暗号化情報 と一致するかで認証が行われています。
それほど難しいアルゴリズムもないので、作成手順が理解できていれば、簡単ではないかと思います。
Nginx で authcode.php へリダイレクトする
今回は、Nginxで secure_link、secure_link_md5 のディレクティブを使用しません。
先に作成した認証用のphpファイル authcode.php へすべてリダイレクトするように設定します。
編集するのは、server ディレクティブが設定されているファイルになります。ここでの例は、/etc/nginx/nginx.conf とします。
...
http {
...
server {
listen 80;
root /var/www/html;
server_name example.com;
...
index index.php index.html index.htm;
...
location /secure/ {
# Nginxの設定では、単純にリダイレクトするだけにします。
rewrite ^.*$ /secure/authcode.php last;
...
}
...
# phpが動作するように設定します。
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
...
}
...
}
|
ここでは、単純に /secure/ へのアクセスは、すべて /secure/authcode.php へリダイレクトしているだけです。
設定ファイルに、日本語を使った場合は、必ず、文字コードをUTF8で保存しましょう。
これを間違えるとNginxの起動で失敗します。
上記のように設定、編集を終えたら、Nginxにて再読み込みを行います。
$ /etc/init.d/nginx reload
...
|
最後に確認してみる
先の例では、以下のような順番でアクセスすれば正しく表示できるはずです。
- http://exmaple.com/securelink.php へアクセスする
- “シークレットリンク” をクリックする
以下の画面が表示されればOKです。
また、失敗した場合は、以下のような画面が表示されるはずです。
もちろん、直に http://exmaple.com/secure/ へアクセスしても上記の403エラーが出力されます。
上記の設定例では、時間切れが1時間後となりますから、うまく表示できていたURLを1時間後にアクセスしてみてください。
同じように、403エラーが出力されるはずです。
Nginx で一時的なセキュアなリンクを使ってみる(secure_link,secure_link_md5ディレクティブを使ってみる) の時と動作が同じですね。
403エラーの画面イメージが異なる場合は、デフォルトの 403 ページには、飛びません。
...
http {
...
server {
...
error_page 403 /403.html;
...
}
...
}
|
上記のようにカスタムエラーページを作成してあげると、そこへ飛んでくれます。
もしくは、先の認証用phpコード(
authcode.php)内でエラーページのイメージを出力すれば同じようなページを出力することができます。
何も設定していない場合は、真っ白な画面が表示されるでしょう。
コメントを投稿 :