nginx + lua-nginx-module で Basic認証時だけ 特定のCache-Controlヘッダの値を付与する処理の実装メモ

 

この記事の概要

下記の2パターンにて Basic認証時だけ 特定のCache-Controlヘッダの値を付与する処理を試しました。

  • nginx の ngx_http_auth_basic_module で Basic認証を実装するパターン
  • nginx の プロキシ先のアプリケーションで Basic認証を実装するパターン ( = nginx で リクエストヘッダ: Authorization 、レスポンスヘッダ: WWW-Authenticate を含む要求応答をプロキシする )

 ユースケースとしては、前段(ブラウザ, CDN, キャッシュサーバ等) で、Basic認証対象のコンテンツだけはキャッシュさせたくないので、特定のCache-Controlの値を付与したいときを想定しています。

Cache-Controlの値によるキャッシュ制御の挙動は、各々(ブラウザ,CDN,キャッシュサーバ等)の仕様を確認してください。

今回は一例として、Basic認証時だけ no-store を付与するという内容で試しています。

 

実装その1. nginx の ngx_http_auth_basic_module で Basic認証を実装するパターン

このパターンでは nginx 自体で Basic認証対象のURLパス を指定しているため、その配下に ヘッダ付与を記述します。( auth_basic, auth_basic_user_file の記述方法については本題からそれるのでこの記事では省略しています。 )

 

デフォルトでは、ngx_http_headers_module の add_header では 一部のステータスコードにヘッダを付与することができない仕様です。

Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). Parameter value can contain variables.

※ 抜粋:Module ngx_http_headers_module

なので、Basic認証のレスポンスの一部 :  401 Unauthorized のときには add_header ではヘッダ付与ができません。クライアントとサーバの中間(CDN,プロキシ) の仕様で 401 レスポンスを ネガティブキャッシュする可能性がある場合など、401 にも 明示的にヘッダ付与したいときには add_header の always パラメタを付与する必要があります。

1 - 1. add_header で 実装するパターン ( 401 は対象外 )

付与対象ステータスコードが、200, 204, 206, 301, 302, 303, 304(すべてのバージョン) または 201(1.3.10) または 307 (1.1.16, 1.0.13) または 308 (1.13.0) のみでよく、

401 レスポンスには付与しなくてよい場合に add_header で書くと下記のような記述ができます。

location /basic/ {
add_header Cache-Control "no-store";
auth_basic "test";
auth_basic_user_file .htpasswd;
}

 応答としては、下記になります。

【Authorization ヘッダ無しでリクエスト の 結果抜粋】
# curl -iv http://******.1773.work/basic/

(リクエストヘッダ)
GET /basic/ HTTP/1.1
User-Agent: curl/7.29.0
Host: ******.1773.work
Accept: */*

(レスポンスヘッダ)
HTTP/1.1 401 Unauthorized
Date: Sun, 18 Aug 2019 02:59:34 GMT
Content-Type: text/html
Content-Length: 195
Connection: keep-alive
WWW-Authenticate: Basic realm="test"

※ Cache-Control が付与されない

 

【Authorization ヘッダありでリクエスト の 結果抜粋】
# curl -iv http://******.1773.work/basic/ -u test:******

(リクエストヘッダ)
GET /basic/ HTTP/1.1
Authorization: Basic ********(hash値)
User-Agent: curl/7.29.0
Host: ******.1773.work
Accept: */*

(レスポンスヘッダ)
HTTP/1.1 200 OK
Date: Sun, 18 Aug 2019 02:59:34 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Thu, 06 Dec 2018 08:16:29 GMT
Connection: keep-alive
ETag: "5c08dadd-f"
Cache-Control: no-store ⇒ Cache-Control が付与される
Accept-Ranges: bytes

 

1 - 2. add_header で 実装するパターン ( すべてのレスポンスコードが対象 )

If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.

※ 抜粋:Module ngx_http_headers_module

401 レスポンスを含む、すべての ステータスコードに も付与したい場合には、add_header の always パラメタを付与する必要があります。( 2019/09/30 修正 : こちらは元々 lua-nginx-module で記述していましたが、alwaysパラメタで設定可能という内容を知り、修正しました。)

location /basic/ {
add_header Cache-Control "no-store" always;
auth_basic "test";
auth_basic_user_file .htpasswd;
}

1.7.5 未満のバージョンのnginxで always が使えないが、lua-nginx-module は利用可能な場合は下記でも同様に全てのステータスコードに付与可能になります。

location /basic/ {
auth_basic "test";
auth_basic_user_file .htpasswd;

header_filter_by_lua_block {
ngx.header["Cache-Control"] = 'no-store';
}
}

401 の 応答にも 付与ができるようになります。

【Authorization ヘッダ無しでリクエスト の 結果抜粋】
# curl -iv http://******.1773.work/basic/

(リクエストヘッダ)
GET /basic/ HTTP/1.1
User-Agent: curl/7.29.0
Host: ******.1773.work
Accept: */*

(レスポンスヘッダ)
HTTP/1.1 401 Unauthorized
Date: Sun, 18 Aug 2019 03:13:05 GMT
Content-Type: text/html
Content-Length: 195
Connection: keep-alive
WWW-Authenticate: Basic realm="test"
Cache-Control: no-store ⇒ Cache-Control が付与される

 

実装その2. nginx の プロキシ先のアプリケーションで Basic認証を実装するパターン

このパターンでは nginx では Basic認証対象のURLパスを管理していません。要求応答ヘッダ(リクエストヘッダ: Authorization 、レスポンスヘッダ: WWW-Authenticate)有無で判定して Cache-Control を付与する例です。

location / {
proxy_pass http://127.0.0.1:****/;

header_filter_by_lua_block {
if ngx.req.get_headers()["Authorization"] ~= nil or ngx.resp.get_headers()["WWW-Authenticate"] ~= nil then
ngx.header["Cache-Control"] = 'no-store'
end
}
}

 応答としては、下記になります。

【Authorization ヘッダ無しでリクエスト の 結果抜粋】
# curl -iv http://******.1773.work/basic/

(リクエストヘッダ)
GET /basic/ HTTP/1.1
User-Agent: curl/7.29.0
Host: ******.1773.work
Accept: */*

(レスポンスヘッダ)
HTTP/1.1 401 Unauthorized
Date: Sun, 18 Aug 2019 04:11:48 GMT
Content-Type: text/html
Content-Length: 180
Connection: keep-alive
WWW-Authenticate: Basic realm="test"
Cache-Control: no-store ⇒ Cache-Control が付与される

 

【Authorization ヘッダありでリクエスト の 結果抜粋】
# curl -iv http://******.1773.work/basic/ -u test:******

(リクエストヘッダ)
GET /basic/ HTTP/1.1
Authorization: Basic ********(hash値)
User-Agent: curl/7.29.0
Host: ******.1773.work
Accept: */*

(レスポンスヘッダ)
HTTP/1.1 200 OK
Date: Sun, 18 Aug 2019 04:11:41 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Last-Modified: Wed, 27 Mar 2019 02:38:45 GMT
ETag: "5c9ae235-264"
Accept-Ranges: bytes
Cache-Control: no-store ⇒ Cache-Control が付与される

 

【Basic認証以外のURLへのリクエスト の 結果抜粋】
# curl -iv http://******.1773.work/

(リクエストヘッダ)
GET / HTTP/1.1
User-Agent: curl/7.29.0
Host: ******.1773.work
Accept: */*

(レスポンスヘッダ)
HTTP/1.1 200 OK
Date: Sun, 18 Aug 2019 04:21:28 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Last-Modified: Wed, 27 Mar 2019 02:38:45 GMT
ETag: "5c9ae235-264"
Accept-Ranges: bytes

※ Cache-Control は付与されない

 

Basic認証時 の Cache-Controlヘッダ付与についてのメモでした。