ngx_http_userid_module の uid_got/uid_set と cookie に書き込まれる uid について

ngx_http_userid_module を使うと nginx でクライアントを識別するための 識別子 を cookie に焼くことができる。

また、cookie に書き込んだあたいは $uid_got/$uid_set の組み込み変数で参照可能でログなどに記録することができる。

例えば、以下のような conf で nginx を起動し、適当にアクセスした場合のログを見てみる

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;

    userid          on;
    userid_name     uid;
    userid_path     /;
    userid_expires  max;

    log_format  main  "time:$time_local\t"
                      'req:$request\t'
                      'cookie:$http_cookie\t'
                      'set_cookie:$sent_http_set_cookie\t'
                      'uid_got:$uid_got\t'
                      'uid_set:$uid_set';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    include /etc/nginx/conf.d/*.conf;
}

ログはこちらになる

time:21/Aug/2020:03:16:37 +0000 req:GET / HTTP/1.1      cookie:-        set_cookie:uid=rBEAAl8/PJUlwAAGAwMEAg==; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/    uid_got:-       uid_set:uid=020011AC953C3F5F0600C02502040303

set_cookie と uid_set(初回はuid_set に値が入って次回以降はuid_gotに値が入る)を見る

set_cookie:uid=rBEAAl8/PJUlwAAGAwMEAg==; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/

uid_set: uid=020011AC953C3F5F0600C02502040303

cookie に書き込まれている識別子は rBEAAl8/PJUlwAAGAwMEAg== だが uid_set で参照できる識別子は 020011AC953C3F5F0600C02502040303 で一致しない。

この辺りを眺めるとどうやら uid_set に対してごにょごにょした値が cookie にセットされるようだった。

uid_set の値から cookie に書き込んでいる値への変換処理はおそらくこの辺りソースコードは正直何やっているのかちゃんと追えなかったのでメーリングリストに書いてある処理で cookie の値から uid_set の値に変換してみる

[1] pry(main)> require 'base64'
=> true
[2] pry(main)> Base64.decode64("rBEAAl8/PJUlwAAGAwMEAg==").unpack("L*").map{|a| sprintf("%08X", a)}.join.upcase
=> "020011AC953C3F5F0600C02502040303"

ちゃんと変換できた。 sprintf("%08X", a) が味噌で8桁で揃えないと先頭が0の場合にデータがかけて微妙に違うデータになる。 これは uid_set が uint32_t で定義されているからだと思う

逆のことをやれば、 uid_set から cookie の値に変換することもできる。

[4] pry(main)> Base64.encode64("020011AC953C3F5F0600C02502040303".downcase.scan(/.{1,8}/).map{|a|  a.to_i(16)}.pack("l*"))
=> "rBEAAl8/PJUlwAAGAwMEAg==\n"