从nginx的cookie中获得用户访问的时间
由于需要跟踪用户行为,在nginx服务端使用user模块开启了nginx的cookie,使用服务器来设置cookie而不是通过程序来设置的好处在于:
1 比较简单,不需要自己写程序维护
2 图片等静态文件也可以设置cookie
本想通过分析log获得用户第一次入站的时间,但通过观察nginx的log,发现它设置的cookie有以下规律:
1 32位的sid,第一个8位和第三个8位的值相同,最后一个8位的值是等差数列
2 第二个8位的后4位相同,前面4位不同
nginx sid样例:
9000A8C0 6E15 AD4D 734A84B1 02180303
9000A8C0 4616 AD4D 734A84B1 02190303
9000A8C0 D616 AD4D 734A84B1 021A0303
鉴于有这么明显的规律,我认定其中必有私货。上IRC问了一下,暂时没人回答,于是决定自己看看源代码。
按图索骥,根据nginx wiki 上列的模块关系,一下可以找到user对应的代码为:
svn cat svn://svn.nginx.org/nginx/trunk/src/http/modules/ngx_http_userid_filter_module.c
nginx的代码非常清楚,代码看起来也比较易读,在534行左右可以看到uid的各个元素的值
ctx->uid_set[0] = htonl(conf->service); // 与服务有关,为定值
ctx->uid_set[1] = htonl((uint32_t) ngx_time()); // 嗯,服务端的时间
ctx->uid_set[2] = htonl(start_value); // 不太清楚,从变量名来看应该为服务启动时间,启动后不会变化
ctx->uid_set[3] = htonl(sequencer_v2); // 一个sequence,每一次都会加,到了一定的阈值再重置
既然这样,那么上面说的第二个8位就是时间戳了。
由于该时间戳通过htonl进行了转换,按network byte order(也就是big endian)编码,我们使用时就需要调用ntohl转换成本地的字节顺序。
简单的c++程序如下:
#include <arpa/inet.h>
#include <iostream>
using namespace std;
int main(int argv, char ** argc){
cout << "ntohl" << endl;
cout << ntohl(0xD616AD4D) << endl;
return 0;
}
输出的结果为 1303189206,嗯,后面的事情,大家都知道了。
如果用php,简单的代码如下:
<?php
$str = "D616AD4D";
$splited = str_split($str, 2);
$splited = array_reverse($splited);
$str = implode('', $splited);
print hexdec($str);
?>
其实就是自己手动实现了一把big endian 到 little endian的转换:将byte的次序换了一下。
以上纯属个人看法,如有不对,希望拍砖,谢谢~