现在的位置: 首页 > 综合 > 正文

COOKIE格式与读写相关

2013年08月24日 ⁄ 综合 ⁄ 共 4169字 ⁄ 字号 评论关闭

1. COOKIE文件格式:

COOKIE文件为操作系统cookies目录下的一堆txt文件。文件名格式为:
<用户名>@<域名>[数字].txt
即,同一个域下可能有多个cookie文件:
elf@sohu[1].txt
elf@sohu[2].txt
elf@sohu[3].txt
文件名中的数字含义不明。实际上,浏览网页时,浏览器会根据cookies目录下index.dat中的索引信息去定位到某一个文件,然后查找相应COOKIE字段值。

COOKIE文件为UNIX格式,只有换行(0x0A)没有回车(0x0D)。每个COOKIE文件内,各字段之间以*分隔,每个字段均包含8行信息:

 

_ntes_nnid                                  // 字段名

456f74e9863f8f4b1a1e37774b0c464d,0            // 字段值

163.com/                                     // 字段所属域

3584                                            // 标志位

3205176064                                // 过期时间(低位)

37425091                                    // 过期时间(高位)

2444768976                                // 创建时间(低位)

30082544                                    // 创建时间(高位)


其中,过期时间和创建时间为FILETIME,需要转成16进制然后拼起来看。标志位标记了一些安全信息,如是否是HTTPONLY(稍后详述)的等等。

2. WININET API对COOKIE的读写

非浏览器客户端想要读写COOKIE,有如下几个函数可用:

  1. InternetGetCookie
  2. InternetSetCookie
  3. InternetGetCookieEx
  4. InternetSetCookieEx

具体参数含义可以参考MSDN,有如下几个地方需要注意的:

1) 上述4个函数的参数lpszCookieName(COOKIE字段名)一般传NULL,而不要按MSDN里说的那样去传一个字段名,否则可能失败。get时,传NULL,会拿到一个类似“name1=value1; name2=value2; ...”这样的字符串,自己去解析一下就好了,但是像标志位、过期时间等信息就丢掉了。set时,传NULL,其它信息(如字段名、值、过期时间)都在lpszCookieData里以固定格式写好传进去:

  1. my_name=my_value; path=/; expires=Sun, 18 Jan 2038 00:00:00 GMT; domain=.sohu.com; HttpOnly  

 

注:上面代码中,时间的格式为"day-month-year hour:minute:second"。

如果名字设置为NULL就会出现一个奇妙的现象,只会插入之后一次设置的cookie,以前插入的就会被查处掉,因为NULL也算成一个lpszCookieName了。这就是为什么经常有人问到 InternetSetCookie为什么只能插入一个cookie呢, 说到底lpszCookieName还是需要的,当然如果只用设置一个cookie可以不需要,毕竟更保险,但是我认为按照MS的说法来做更正确一些,如果要设置多个cookie
那么lpszCookieName必须要, 格式如下:

CString cookie="1; path=/; expires=Sun, 18 Jan 2038 00:00:00 GMT; domain=test.com";
    InternetSetCookie("http://test.com", "test1", cookie);

cookie="2; path=/; expires=Sun, 18 Jan 2038 00:00:00 GMT; domain=test.com";
    InternetSetCookie("http://test.com", "test2", cookie);

插入后 cookie文件中内容如下:

test1
1
test.com/
0
2350186496
32111674
3484819392
30224948
*
test2
2
test.com/
0
2350186496
32111674
3484819392
30224948
*

可以看到已经插入成功,这个插入函数要注意的地方就是 InternetSetCookie的第三个参数lpszCookieData 它的格式不是单纯的 一个数值,而是一个my_value; path=/; expires=Sun,
18 Jan 2038 00:00:00 GMT
; domain=.test.com
的格式。错误的写法最容易写成:

CString cookie="1";
    InternetSetCookie("http://test.com", "test1", cookie);

cookie="2";
    InternetSetCookie("http://test.com", "test2", cookie);

这样是不会插入成功的,因为cookie的格式决定了,它有一个有效时间,所在域。所以格式必须完整。

2)在get时,如果参数lpszURL为1级域名,那么会同时拿到该域名下所有2级域名及子目录下的符合条件的COOKIE。如果参数lpszURL为2级域名,会同时拿到所有子目录下的符合条件的COOKIE。如http://sohu.com,会拿到http://bai.sohu.com下的COOKIE。

3) VISTA和WIN7,且IE7或IE8时,IE默认开启保护模式,此时IE读写的cookie不是在cookies目录下,而是cookies目录的low目录下。而客户端是从哪个目录下去读取COOKIE,就取决于当前客户端进程的权限:普通权限进程拿cookies目录,受限(LOW)权限拿LOW目录。如果进程是以普通权限启动的,想拿LOW目录下的COOKIE,就需要以低权限启动另外一个进程,用子进程去拿:

  1. {  
  2.     HANDLE hProcess = GetCurrentProcess();  
  3.     HANDLE hToken = NULL, hTokenNew = NULL;  
  4.     PSID plntegritySicl = NULL;  
  5.     TOKEN_MANDATORY_LABEL tml = {0};  
  6.     PROCESS_INFORMATION procInfo = {0};  
  7.     STARTUPINFO StartupInfo = {0};  
  8.     ULONG ExitCode = 0;  
  9.       
  10.     if (!ImpersonateSelf(SecurityImpersonation)) {  
  11.         return FALSE;  
  12.     }  
  13.     // 指定低权限:  
  14.     if (!ConvertStringSidToSid(SDDL_ML_LOW, &plntegritySicl)) {  
  15.         return FALSE;  
  16.     }  
  17.     BOOL bRes = FALSE;  
  18.     if (OpenProcessToken(hProcess, MAXIMUM_ALLOWED, &hToken)) {  
  19.         if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hTokenNew)) {  
  20.             tml.Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;  
  21.             tml.Label.Sid = plntegritySicl;  
  22.             if (SetTokenInformation(hTokenNew, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(plntegritySicl))) {  
  23.                 if (CreateProcessAsUser(hTokenNew, NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &procInfo)) {  
  24.                     bRes = TRUE;  
  25.                 }  
  26.                 if (bWait) {  
  27.                     WaitForSingleObject(procInfo.hProcess, 10 * 1000);  
  28.                 }  
  29.             }  
  30.             CloseHandle(hTokenNew);  
  31.         }  
  32.         CloseHandle(hToken);  
  33.     }  
  34.     return bRes;  
  35. }  

 


4) 在IE7及以后,cookie引入了一个属性HTTPONLY,值为0x2000。该标志是一个安全性标志,如果一个COOKIE字段具有该属性(标志位具有0x2000这一位),则网页脚本无法获取该字段,此字段只存在于http请求的HEADER中。而对于客户端,则有:
IE6或IE7环境下:客户端无法通过InternetGetCookie获取此字段值,只能读取COOKIE文本,然后手动解析(参考第一部分:COOKIE文件格式)。
IE8环境下:客户端可以通过InternetGetCookieEx,且参数dwFlags包含0x2000,来获取此字段值。

抱歉!评论已关闭.