NGINXのSecureLinkモジュールを使ってみる

突然ですがSecureLinkモジュールとはなんぞや、というところですが、簡単に言うと、サービス登録時のメールアドレス確認で、下記の様なメールで見たことがあるような、一定時間のみ有効な時限式URLの認証機能を提供するモジュールです。


通常このような機能を作成する場合、URLの発行、利用期限の管理含め、基本的にはいわゆるPHP、Ruby、Python、Javaなどのサーバサイドアプリケーションで実装して利用しますが、このSecureLinkモジュールはこのうちの利用期限管理(URLの正当性検証)をnginx側で処理してくれるものになります。
そのため、時限式URLに絡めて、事前に入力されたユーザー情報を参照して〜といった、上記のメール画像のような機能には適さないですが、例えば、特定の静的ファイルを時限式URLで不特定多数に配布したい、といった場合であれば有効であると言えます。


長い前置きはさておき、以下からは実際に設定していきます。



まず、このモジュールはnginxの標準モジュールとしては提供されていないため、nginxのconfigure時に--with-http_secure_link_moduleオプションを付けてビルドし、有効化します。

一番簡単な設定方法としては、モジュールの公式ドキュメントこちらのページ(by レンタルサーバー・自宅サーバー設定・構築のヒント)で紹介されているとおり設定すると基本的に動きます。

で、同じ内容で紹介してもあまり芸がないので、今回はほんの少しだけトリッキーな設定(ただの応用)での構築をここで記載してみます。

まず、構成を下記の様に設定するものとします。

パス設定
/var/www/example.com/public
└ドキュメントルート
/var/www/example.com/secure
└セキュアファイル設置場所


URL
https://example.com
└通常URL
https://example.com/secure
└セキュアリンクURL


通常の設定

ここまでの設定で、通常設定すると下記の様な設定になります。
server {
    root    /var/www/example.com/public;
    index   index.html;
    # SecureLinkアクセス用URI
    location /secure/ {
        alias /var/www/example.com/secure;
        # 公開鍵のパラメータ k=公開鍵&t=タイムスタンプ のパラメータを与える設定
        secure_link $arg_k,$arg_t;
        # 公開鍵レシピ
        secure_link_md5 YOUR_SECRET_KEY_WITH$uri?$arg_t;
        if ($secure_link = "") {
           # 認証NGの場合404を返却
           return 404;
        }
        if ($secure_link = "0") {
            # 有効期限切れの場合は403を返却
            return 403;
        }

        try_files /$request_uri =404;
    }
}
上記設定では、例えば https://example.com/secure/secret.html?k=OqjJ-smKxgnNTCGYz78TOg&t=1531815176 というURLにアクセスすると、パラメータkの公開鍵とtのタイムスタンプがそれぞれ正しければsecret.htmlのファイルを閲覧することができます。
/secure/パス以下は、ドキュメントルート外の/var/www/example.com/secureを参照したいので、alias で別途パスを指定してます。(ここでrootディレクティブで指定すると、/secureの参照先が/var/www/example.com/secure/secure 以下を参照する事となり、恐らく想定した通りのパスを見てくれません)

セキュアリンクモジュールを使用した場合、パラメータまで一致していて初めてアクセスできるので、これらのURLパラメータを削除して、直接 https://example.com/secure/secret.html にアクセスしても、secret.htmlは閲覧できません。
が、今回はもうちょっとURLをそれっぽくしたい


セキュアリンクのURLをカスタムしたい

https://example.com/secure/OqjJ-smKxgnNTCGYz78TOg/secret.html?t=1531815176

というURLのフォーマットにしたいと思ったので、下記の様にアレンジしてみました。

    # SecureLinkアクセス用URI
    location ~ ^/secure/(?<pubkey>[0-9a-zA-Z_\-]+)/(?<filepath>.+) {
        alias /var/www/example.com/secure;
        # Public key (URI)
        secure_link $pubkey,$arg_t;
        # Secret key
        secure_link_md5 "YOUR_SECRET_KEY_WITH$filepath?$secure_link_expires";
        # Invalid key
        if ($secure_link = "") {
           return 404;
        }
        # timeout
        if ($secure_link = "0") {
            return 403;
        }
        try_files /$filepath =404;
    }

今回のポイント

ポイントはlocationディレクティブを名前付き正規表現でパラメータを判定できるようにして、その名前(ここでは変数$pubkey)とURLパラメータ(t)をsecure_linkに引数として渡しているところです。
また、対象のファイルは同じく名前付き正規表現で変数$filepathに格納しています。

すべての認証が成功した際に、try_files$filepathを確認し、なければ404を返す様にしています。

最近作ったアプリの話

先日、コナミ社の提供している コナステ のダウンロードコンテンツゲームを1クリックで起動できるアプリを作り、公開した。 Ks Game Launcher  ( Github ) 作った理由として、インストール時に作成されたショートカットをクリックするとブラウザが起動し、ログインし...