ブログ | NGINX

NGINX および NGINX Plus のセキュア リンク モジュールを使用して URL を保護する

NGINX-F5 水平黒タイプ RGB の一部
クナル・パリアーニ サムネイル
クナル・パリアーニ
2016 年 7 月 29 日公開

オープンソースのNGINXソフトウェアとNGINX Plus はどちらも、Web サーバー、リバース プロキシ、コンテンツのキャッシュとして非常に安全で信頼性があります。 権限のないクライアントによるアクセスに対する追加の保護として、 Secure Link モジュールのディレクティブを使用して、クライアントが要求するアセットの URL に特定のハッシュ文字列を含めるように要求できます。

このブログ投稿では、Secure Link モジュールに実装されている 2 つの方法を構成する方法について説明します。 サンプル構成スニペットは HTML およびメディア プレイリスト ファイルを保護しますが、任意のタイプの HTTP URL に適用できます。 これらの方法は NGINX と NGINX Plus の両方に適用されますが、簡潔にするために、このブログの残りの部分では NGINX Plus のみについて説明します。

セキュアリンクモジュールのメソッドの概要

Secure Link モジュールは、 HTTP 要求の URL 内のエンコードされた文字列と、その要求に対して計算された文字列を比較して、要求されたリソースの有効性を検証します。 リンクの有効期間が限られており、その期間が過ぎると、そのリンクは古いものと見なされます。 これらのチェックのステータスは$secure_link変数にキャプチャされ、処理のフローを制御するために使用されます。

前述のように、モジュールは 2 つのメソッドを提供します。 特定のhttpserver 、またはlocationコンテキストで構成できるのは、そのうちの 1 つだけです。

  • 最初のよりシンプルなモードはsecure_link_secretディレクティブによって有効になります。 エンコードされた文字列は、URL の最後の部分と NGINX Plus 設定で定義された秘密の単語の 2 つのテキスト文字列の連結に基づいて計算された MD5 ハッシュです。 (最初のテキスト文字列の詳細については、 「基本的なセキュリティ保護された URL の使用」を参照してください。)

    保護されたリソースにアクセスするには、クライアントは URL プレフィックスの直後にハッシュを含める必要があります。これは、スラッシュのない任意の文字列です。 このサンプル URL では、プレフィックスはvideosで、保護されたリソースはファイルbunny.m3u8です。

    /videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8

    この方法の使用例の 1 つは、ユーザーが共有のために画像またはドキュメントをサーバーにアップロードしたが、公式リンクが公開されるまでファイル名を知っているユーザーがアクセスできないようにしたい場合です。

  • 2 番目のより柔軟な方法は、 secure_linkおよびsecure_link_md5ディレクティブによって有効になります。 ここでエンコードされた文字列は、NGINX Plus 構成ファイルで定義された変数の MD5 ハッシュです。 最も一般的には、特定のクライアント IP アドレスへのアクセスを制限するために$remote_addr変数が含まれますが、 User-Agentヘッダーをキャプチャして特定のブラウザーへのアクセスを制限する$http_user_agentなどの他の値を使用することもできます。

    オプションで、ハッシュが正しい場合でも URL が機能しなくなる有効期限を指定できます。

    ハッシュを指定するには、クライアントはリクエスト URL にmd5引数を追加する必要があります。 ハッシュされた文字列に有効期限が含まれている場合、クライアントは、保護されたファイルpricelist.htmlを要求する次のサンプル URL のように、有効期限を指定するためにexpires引数も追加する必要があります。

    /files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740

Secure Link モジュールは、nginx.org のビルド済みオープンソース NGINX バイナリ、オペレーティング システム ベンダーが提供する NGINX パッケージ、およびNGINX Plusに含まれています。 ソースから NGINX をビルドする場合、デフォルトでは含まれません。configure コマンド--with-http_secure_link_module引数を含めることで有効にします。

基本的なセキュリティ保護された URL の使用

URL を保護するより基本的な方法は、 secure_link_secretディレクティブを使用することです。 次のサンプル スニペットでは、 /bunny.m3u8という名前の HTTP ライブ ストリーミング (HLS) メディア プレイリスト ファイルを保護します。 これは/opt/secure/hlsディレクトリに保存されますが、 videosプレフィックスで始まる URL を使用してクライアントに公開されます。

server {
listen 80;
server_name secure-link-demo;

location /videos {
secure_link_secret enigma;
if ($secure_link = "") { return 403; }

rewrite ^ /secure/$secure_link;
}

location /secure {
internal;
root /opt;
}
}

この構成では、ファイル/opt/secure/hls/bunny.m3u8にアクセスするには、クライアントは次の URL を提示する必要があります。

/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8

ハッシュ化された文字列はプレフィックスの直後に続きます。プレフィックスはスラッシュのない任意の文字列です (ここではvideos )。

ハッシュは、2 つの要素を連結したテキスト文字列に対して計算されます。

  • ハッシュに続く URL の部分。ここではhls/bunny.m3u8 です
  • secure_link_secretディレクティブへのパラメータ。ここではenigma です

クライアントのリクエスト URL に正しいハッシュがない場合、NGINX Plus は$secure_link変数を空の文字列に設定します。 の もし テストが失敗し、NGINX Plusは 403 禁断 HTTP 応答のステータス コード。

それ以外の場合 (ハッシュが正しいことを意味します)、書き換えディレクティブは URL を書き換えます。この例では、 /secure/hls/bunny.m3u8になります ( $secure_link変数はハッシュに続く URL の部分をキャプチャします)。 /secureで始まる URL は、2 番目のロケーションブロックによって処理されます。 そのブロック内のrootディレクティブは、要求されたファイルのルート ディレクトリとして/opt を設定し、 internalディレクティブは、ブロックが内部で生成された要求にのみ使用されることを指定します。

基本的なセキュリティ保護された URL のクライアント側でのハッシュの生成

クライアントが URL に含める必要がある 16 進形式の MD5 ハッシュを取得するには、 -hexオプションを指定してopenssl md5コマンドを実行します。

# echo -n 'hls/bunny.m3u8enigma' | openssl md5 -hex (stdin)= 80e2dfecb5f54513ad4e2e6217d36fd4

プログラムによるハッシュの生成については、 「プログラムによるハッシュの生成」を参照してください。

基本的なセキュリティ保護された URL に対するサーバー応答

次のサンプルcurlコマンドは、サーバーがさまざまなセキュリティ保護された URL にどのように応答するかを示しています。

URLに正しいMD5ハッシュが含まれている場合、応答は200わかりました

# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8 | head -n 1 HTTP/1.1 200 OK

MD5ハッシュが間違っている場合、応答は次のようになります。403禁断

# curl -I http://secure-link-demo/videos/2c5e80de986b6fc80dd33e16cf824123/hls/bunny.m3u8 | head -n 1 HTTP/1.1 403 禁止

bunny.m3u8のハッシュが別のファイルに使用されている場合、応答も403禁断

# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hs/oven.m3u8 | head -n 1 HTTP/1.1 403 禁止

期限切れの保護された URL の使用

URL を保護するためのより柔軟な方法として、 secure_linkおよびsecure_link_md5ディレクティブを使用します。 この例では、これらを使用して、IP アドレス 192.168.33.14 のクライアントからのみ、2016 年 12 月 31 日までのみ、 /var/www/ files/pricelist.html ファイルへのアクセスを許可します。

仮想サーバーはポート 80 でリッスンし、 location /filesブロックの下にあるすべてのセキュリティ保護された HTTP 要求を処理します。ここで、 rootディレクティブは、要求されたファイルのルート ディレクトリとして/var/wwwを設定します。

secure_linkディレクティブは、リクエスト URL 内の引数を取得する 2 つの変数を定義します。 $arg_md5md5引数の値に設定され、 $arg_expires はexpires引数の値に設定されています。

secure_link_md5ディレクティブは、リクエストの MD5 値を生成するためにハッシュされる式を定義します。URL 処理中に、ハッシュは$arg_md5の値と比較されます。 ここでのサンプル式には、リクエストで渡された有効期限 ( $secure_link_expires変数でキャプチャされます)、URL ( $uri )、クライアント IP アドレス ( $remote_addr )、および単語enigmaが含まれています。

server {
listen 80;
server_name secure-link-demo;

location /files {
root /var/www;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr enigma";

if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
}

この設定では、 /var/www/files/pricelist.htmlにアクセスするには、IP アドレス 192.168.33.14 のクライアントが2016 年 12 月 31 日土曜日 23:59:00 UTCまでに次のリクエスト URL を送信する必要があります。

/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740

クライアントから送信された URL のハッシュ ( $arg_md5変数でキャプチャ) がsecure_link_md5ディレクティブから計算されたハッシュと一致しない場合、NGINX Plus は$secure_link変数を空の文字列に設定します。 ifテストが失敗し、NGINX Plusが403HTTP 応答の禁止ステータス コード。

ハッシュが一致してもリンクの有効期限が切れている場合は、NGINX Plusは $セキュアリンク 変数に 0; 再び もし テストは失敗しますが、今回はNGINX Plusが 410 消えた HTTP 応答のステータス コード。

クライアント上でハッシュと有効期限を生成する

ここで、クライアントが URL に含めるmd5およびexpires引数をどのように計算するかを見てみましょう。

最初のステップは、有効期限に相当する Unix 時間を決定することです。その値は、 $secure_link_expires変数の形式でハッシュ式に含まれているためです。 Unix 時間 (エポック(1970-01-01 00:00:00 UTC)からの秒数) を取得するには、 -dオプションと+%sフォーマット指定子を指定したdateコマンドを使用します。

この例では、有効期限をSat Dec 31 23:59:00 UTC 2016に設定しているので、コマンドは次のようになります。

#日付 -d "2016-12-31 23:59" +%s1483228740

クライアントは、この値をリクエスト URL のexpires=1483228740引数として含めます。

ここで、 secure_link_md5ディレクティブで定義された文字列 ( $secure_link_expires$uri$remote_addr) を 3 つのコマンドで実行します。

  • -binaryオプションを指定したopenssl md5コマンドは、バイナリ形式で MD5 ハッシュを生成します。
  • openssl base64コマンドは、ハッシュ値にBase64エンコーディングを適用します。
  • trコマンドは、プラス記号 ( + ) をハイフン ( - ) に、スラッシュ ( / ) をアンダースコア ( _ ) に置き換え、エンコードされた値から等号 ( = ) を削除します。

この例では、完全なコマンドは次のようになります。

# echo -n '1483228740/files/pricelist.html192.168.33.14 enigma' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = AUEnXC7T-Tfv9WLsWbf-mw

クライアントは、この値を要求 URL のmd5=AUEnXC7T-Tfv9WLsWbf-mw引数として含めます。

プログラムによるハッシュの生成

NGINX Plus Web サーバーがアプリケーション サーバーから動的コンテンツを提供している場合、NGINX Plus とアプリケーション サーバーの両方で同じセキュリティ保護された URL を使用する必要があります。 URL 内のmd5引数のハッシュをプログラムで生成できます。 次の Node.js 関数は、上記の NGINX Plus 設定スニペットで定義されたハッシュと一致するハッシュを生成します。 有効期限、URL、クライアント IP アドレス、および秘密の単語を引数として受け取り、Base64 でエンコードされたバイナリ形式の MD5 ハッシュを返します。

var crypto = require("crypto");

function generateSecurePathHash(expires, url, client_ip, secret) {
if (!expires || !url || !client_ip || !secret) {
return undefined;
}

var input = expires + url + client_ip + " " + secret;
var binaryHash = crypto.createHash("md5").update(input).digest();
var base64Value = new Buffer(binaryHash).toString('base64');
return base64Value.replace(/=/g, '').replace(/+/g, '-').replace(///g, '_');
}

現在の例のハッシュを計算するには、次の引数を渡します。

generateSecurePathHash(new Date('12/31/2016 23:59:00').getTime()), '/files/pricelist.html', “192.168.33.14”, "enigma");

有効期限付きの保護された URL に対するサーバーの応答

次のサンプルcurlコマンドは、サーバーがセキュリティ保護された URL にどのように応答するかを示しています。

IPアドレス192.168.33.14のクライアントが正しいMD5ハッシュと有効期限を入力すれば、応答は次のようになります。200わかりました

# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 200 OK

異なるIPアドレスを持つクライアントが同じURLを送信した場合、応答は403禁断

# curl -I --interface "192.168.33.33" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 403 禁止

md5引数のハッシュ値が正しくない場合、応答は403禁断

# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=qeUNjiY2FTIVMaXUsxG-7w&expires=1483228740' | head -n 1 HTTP/1.1 403 禁止

URLの有効期限が切れている場合( expires引数で指定された日付が過去である場合)、応答は次のようになります。410消えた

# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=Z2rNva2InyVcRTlhqAkT4Q&expires=1467417540' | head -n 1 HTTP/1.1 410 消えた

例 – 有効期限付きのセグメントファイルの保護

以下は、メディア アセットのプレイリストとセグメント ファイルの両方を保護するために使用される、有効期限付きのセキュリティ保護された URL の別の例です。

前の例との 1 つの違いは、 $file_name変数でファイル名をキャプチャし、 secure_link_md5 ディレクティブに渡すときに、プレイリスト ( .m3u8ファイル) と HLS セグメント ( .tsファイル) から拡張子を削除するためのマップ構成ブロックをここに追加していることです。 これは、プレイリストだけでなく、個々の.tsセグメントに対するリクエストを保護するために役立ちます。

最初の例とのもう 1 つの違いは、特定の Web ブラウザー上のクライアントへのアクセスを制限するために (たとえば、URL が Safari では機能するが、Chrome や Firefox では機能しないなど) 、 secure_link_md5ディレクティブに $http_user_agent 変数 ( User-Agentヘッダーをキャプチャ) を含めることです。

map $uri $file_name {
デフォルトなし;
"~*/s/(?<name>.*).m3u8" $name;
"~*/s/(?<name>.*).ts" $name;
}

server {
listen 80;
server_name secure-link-demo;

location /s {
root /opt;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$file_name$http_user_agent enigma";

if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
}

まとめ

NGINX の Secure Link モジュールを使用すると、URL の特定の部分のハッシュなどのエンコードされたデータを追加することで、ファイルを不正アクセスから保護できます。 有効期限を追加すると、リンクの有効期間も制限され、セキュリティがさらに強化されます。

NGINX Plus をお試しいただくには、今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、使用事例についてご相談ください


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"