从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的次序换了一下。

以上纯属个人看法,如有不对,希望拍砖,谢谢~

 

 

- to blog -

blog built using the cayman-theme by Jason Long. LICENSE