Nginxのtoken binding実装を試す

20181016追記
Remove support for Token Binding
https://chromium.googlesource.com/chromium/src/+/2243e8002e3025b3f8386c13be7437fc8b597e2a

chromeの実装は削除されました下記も合わせて参照のこと
https://groups.google.com/a/chromium.org/forum/?nomobile=true#!topic/blink-dev/OkdLUyYmY1E

Token Binding

CookieやOAuth2.0のトークンはbearer tokenと呼ばれ、そのトークンを持ってる人であれば使用することができます。Token Bindingは、各TLSコネクション固有の秘密鍵で署名することで、第三者による別のコネクションにおけるそれらの使用を制限できるものです。


仕様及びユースケースについては、IETFで仕様策定中のドキュメントを参照ください

ngx_token_binding

GoogleがNginxのtoken bindingモジュールを公開していたので試す
https://github.com/google/ngx_token_binding

ビルド
# ngx_token_binding 準備
git clone https://github.com/google/ngx_token_binding.git
cd ./ngx_token_binding 
git submodule update --init
cd ../

# openssl に変更を加える
git clone https://github.com/openssl/openssl.git
vim ./openssl/ssl/t1_lib.c

git diff
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index ce728b0..e2e01bb 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2461,7 +2461,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
          * callback and record the extension number so that an appropriate
          * ServerHello may be later returned.
          */
-        else if (!s->hit) {
+        else {
             if (custom_ext_parse(s, 1, currext->type,
                     PACKET_data(&currext->data),
                     PACKET_remaining(&currext->data), al) <= 0)

#ビルド
wget https://nginx.org/download/nginx-1.11.6.tar.gz
tar zxvf nginx-1.11.6.tar.gz
cd ./nginx-1.11.6/
./configure --with-http_ssl_module --with-openssl=/home/vagrant/openssl/ --addmodule=/home/vagrant/ngx_token_binding

make
sudo make install


nginx.conf

    server {
        listen       80;
        server_name  localhost;
        add_header set-cookie id=test;
    }
    server {
        listen       443 ssl ;
        server_name  localhost;

        token_binding on;
        token_binding_cookie all;
        token_binding_secret secret;

        ssl_certificate /home/vagrant/server.crt;
        ssl_certificate_key /home/vagrant/server.key;

        location / {
            proxy_pass http://127.0.0.1:80;
        }
    }

試す

ChromeのCanary buildがToken Bindingに対応しているので (chrome://flags/ から Token Bindingを有効にする)、それでNginxに接続する。
今回は単純に、ブラウザと単一のサーバとの通信を行い、CookieにToken Bindingのパラメータがつくことを確認する(ユースケースのFirst-party Use Cases)


ブラウザからサーバに複数回アクセスし、デベロッパーツールを確認する

レスポンスのset-cookie及び、リクエストのcookieに文字列が付与されていることが確認できる。


あわせて、サーバ側のログでは 「id=test」のcookieとして認識されていることも確認できる

tail /var/log/nginx/nginx-https.log
192.168.0.1 - - [24/Nov/2016:16:09:17 +0000] "GET / HTTP/1.1" 200 cookie: id=test 


流れにするとこんな感じ


このCookieはもちろん他のブラウザにセットしても正しく使用することはできない