やりたいこと
ブラウザ <-- http --> nginx(proxy) <-- https --> web
この場合、webサイトからcookieが送られて来たときに secure
属性が付いていると、ブラウザがcookieを保存してくれない。(本来httpsでしか送られてこないものがhttpで送られて来たのでブラウザ側で落としている?)
結果、ログインが必要なサイトが使えない。
ヘッダのSet-cookieが↓みたいな感じになっているので、ヘッダ書き換えて secure
属性落としたい。
Set-Cookie: xxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; path=/; secure; httponly
apacheのmod_headersなら結構楽にできるらしいけど、nginxでできないものかと調べてた時にlua-nginx-moduleを発見したのでこれを使ってみる。
公式ドキュメント 読むと、今回やりたいことは header_filter_by_lua_block
で実現できそう。
nginxインストール
luaモジュールを使うためにはnginxをソースからビルドしないといけないみたいです。めんどくさいですね。
今回はluaモジュールが使えるdocker imageを使うことにします。
$ docker pull firesh/nginx-lua
ソースからビルドする方法は公式のgithubに手順が書いてあるのでそちらを参考に
https://github.com/openresty/lua-nginx-module#installation
dockerでnginxを動かす
$ mkdir -p nginx/conf.d
$ vi nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
log_format main ' - [] "" '
'0 "" '
'"" ""';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
$ vi nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
proxy_pass https://hogehoge.com; # proxyしたいwebサイトのURL
header_filter_by_lua_block {
local cookie = ngx.header["Set-Cookie"];
if cookie and type (cookie) == "string" then
cookie = string.gsub(cookie, "secure; ", "");
ngx.header["Set-Cookie"] = cookie;
end
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
$ vi Dockerfile
FROM firesh/nginx-lua
ADD nginx /etc/nginx
EXPOSE 80
$ docker build -t nginx-lua .
$ docker run -p 80:80 nginx-lua
これで localhost
にアクセスすると hogehoge.com
にプロキシしてくれるようになります。
パケットをみて secure
属性が落ちているか確認します。
$ sudo tcpdump -i any port 80 host localhost -A
...
12:17:41.505396 IP 127.0.0.1.80 > 127.0.0.1.58811: Flags [P.], seq 1546:13748, ack 1310, win 10879, options [nop,nop,TS val 2075176958 ecr 2075176608], length 12202: HTTP: HTTP/1.1 200 OK
....E./...@.@............P.....v..=...*.-......
{...{...HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Sun, 04 Feb 2018 03:19:24 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 11341
Connection: keep-alive
X-Powered-By: PHP/5.4.45
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: xxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; path=/; httponly ←書き換えに成功してsecure属性が落ちてる
Content-Security-Policy: default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self';connect-src 'self';media-src 'self'
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: Sameorigin
X-Robots-Tag: none
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
...
実際にログインが必要なサイトも使えるようになることが確認できました。
まとめ
- lua-nginx-moduleはすごく使える
- でもソースからnginxビルドするのすごく面倒、luaモジュール入ってるdocker imageも常に最新版に追従している訳ではない
- 趣味ならいいけど仕事で使う場合nginxのバージョンアップする時とか動作確認・テストめんどくさそう
- 誰かlua-nginx-module入ってるnginxのdocker imageのメンテナンス頼む(他力本願