1. 程式人生 > >Cookie檔案說明及IE的Cookie檔案格式

Cookie檔案說明及IE的Cookie檔案格式

               

1、Cookie檔案的實質

  Cookie實際上是Web服務端與客戶端(典型的是瀏覽器)互動時彼此傳遞的一部分內容,內容可以是任意的,但要在允許的長度範圍之內。客戶端會將它儲存在本地機器上(如IE便會儲存在本地的一個txt檔案中),由客戶端程式對其進行管理,過期的Cookie會自動刪除。每當客戶端訪問某個域下某個目錄中的網頁時,便會將儲存在本地並且屬於那個域下對應目錄的有效Cookie資訊附在網頁請求的頭部資訊當中一併傳送給服務端。

2、Cookie檔案的儲存位置

  不同的客戶端,其Cookie的儲存方式、儲存位置各不相同,這裡只說一下Windows系統中IE的Cookie檔案儲存位置。

  在Windows 2000/XP系統中,Cookie預設儲存在C:/Documents and Settings/<username>/Cookies/目錄下(此處的<username>為你登入系統時使用的使用者名稱,在開始->執行中輸入cookies便可開啟該目錄),命名規則為<username>@<domain>.txt。

    重點:COOKIE檔名格式為:你的使用者名稱@產生的COOKIE的網頁檔案所在的WEB目錄[COOKIE改變的次數].txt

  與2000/XP不同的是,在Windows 95/98/ME系統中Cookie檔案預設是儲存在C:/Windows/Cookies/目錄下的。

3、Cookie檔案的格式

  IE的Cookie檔案實際上就是一個txt文字檔案,只不過換行符標記為Unix換行標記(0x0A),由於記事本對Unix換行標記不相容,開啟後內容全在一行看起來不方便,我們可以用EditPlus或UltraEdit-32開啟,開啟之後,會看到形式如下的內容:namevaluedomain/160012633827843002089645278196830020892*每一行的內容說明:

英文說明:Line Summary1 The Variable Name2 The Value for the Variable3 The Website of the Cookie’s Owner4 Optional Flags5 The Most Significant Integer for Expired Time, in FILETIME Format6 The Least Significant Integer for Expired Time, in FILETIME Format7 The Most Significant Integer for Creation Time, in FILETIME Format8 The Least Significant Integer for Creation Time, in FILETIME Format9 The Cookie Record Delimiter (a * character)

中文說明:第一行 Cookie變數名第二行 Cookie變數值第三行 該Cookie變數所屬域,形如csdn.net/、blog.csdn.net/或blog.csdn.net/lixianlin/第四行 可選標誌第五行 該Cookie過期時間(FILETIME格式)的高位整數第六行 該Cookie過期時間(FILETIME格式)的低位整數第七行 該Cookie建立時間(FILETIME格式)的高位整數第八行 該Cookie建立時間(FILETIME格式)的低位整數第九行 Cookie記錄分隔符(為一個星號* )

補充一下,第三行中Cookie變數所屬域,如csdn.net/,它是一個根域,也就是一級域,表示該Cookie變數在該根域下的所有目錄中的網頁都有效,不管訪問該域下的哪個目錄中的網頁,瀏覽器都會將該Cookie資訊附在網頁頭部資訊當中傳送給服務端;blog.csdn.net/,是一個二級域,表示該Cookie只對blog這個二級域下目錄中的網頁有效;blog.csdn.net/lixianlin/,是一個二級域下的目錄,只有訪問blog這個二級域下lixianlin這個目錄中的網頁時,才會把該Cookie資訊附在請求頭部資訊當中傳送給服務端。需要指出的是csdn.net/和www.csdn.net/並不相同,前者是根域,後者是一個二級域,只是人們習慣了www這樣的形式,所以大多數的網站首頁都用http://www.xxx.com/這樣的二級域來訪問。

附FILETIME格式定義:typedef struct _FILETIME {    DWORD dwLowDateTime;    DWORD dwHighDateTime;} FILETIME, *PFILETIME, *LPFILETIME;

1. COOKIE檔案格式:

COOKIE檔案為作業系統cookies目錄下的一堆txt檔案。檔名格式為:<使用者名稱>@<域名>[數字].txt即,同一個域下可能有多個cookie檔案:[email protected][1].txt[email protected][2].txt[email protected][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,有如下幾個函式可用:

InternetGetCookie InternetSetCookie InternetGetCookieEx InternetSetCookieEx 具體引數含義可以參考MSDN,有如下幾個地方需要注意的:

1) 上述4個函式的引數lpszCookieName(COOKIE欄位名)一般傳NULL,而不要按MSDN裡說的那樣去傳一個欄位名,否則可能失敗。get時,傳NULL,會拿到一個類似“name1=value1; name2=value2; ...”這樣的字串,自己去解析一下就好了,但是像標誌位、過期時間等資訊就丟掉了。set時,傳NULL,其它資訊(如欄位名、值、過期時間)都在lpszCookieData裡以固定格式寫好傳進去:

view plaincopy to clipboardprint?my_name=my_value; path=/; expires=Thu, 07-Mar-13 09:15:47 GMT; domain=.sohu.com; HttpOnly  my_name=my_value; path=/; expires=Thu, 07-Mar-13 09:15:47 GMT; domain=.sohu.com; HttpOnly

注:上面程式碼中,時間的格式為"day-month-year hour:minute:second"。

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目錄。以PinyinUp.exe為例,因為輸入法的程序總是以普通許可權啟動的,想拿LOW目錄下的COOKIE,就需要以低許可權啟動另外一個程序,用子程序去拿:

view plaincopy to clipboardprint?{       HANDLE hProcess = GetCurrentProcess();       HANDLE hToken = NULL, hTokenNew = NULL;       PSID plntegritySicl = NULL;       TOKEN_MANDATORY_LABEL tml = {0};       PROCESS_INFORMATION procInfo = {0};       STARTUPINFO StartupInfo = {0};       ULONG ExitCode = 0;              if (!ImpersonateSelf(SecurityImpersonation)) {           return FALSE;       }       // 指定低許可權:       if (!ConvertStringSidToSid(SDDL_ML_LOW, &plntegritySicl)) {           return FALSE;       }       BOOL bRes = FALSE;       if (OpenProcessToken(hProcess, MAXIMUM_ALLOWED, &hToken)) {           if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hTokenNew)) {               tml.Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;               tml.Label.Sid = plntegritySicl;               if (SetTokenInformation(hTokenNew, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(plntegritySicl))) {                   if (CreateProcessAsUser(hTokenNew, NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &procInfo)) {                       bRes = TRUE;                   }                   if (bWait) {                       WaitForSingleObject(procInfo.hProcess, 10 * 1000);                   }               }               CloseHandle(hTokenNew);           }           CloseHandle(hToken);       }       return bRes;   }  {    HANDLE hProcess = GetCurrentProcess();    HANDLE hToken = NULL, hTokenNew = NULL;    PSID plntegritySicl = NULL;    TOKEN_MANDATORY_LABEL tml = {0};    PROCESS_INFORMATION procInfo = {0};    STARTUPINFO StartupInfo = {0};    ULONG ExitCode = 0;        if (!ImpersonateSelf(SecurityImpersonation)) {        return FALSE;    }    // 指定低許可權:    if (!ConvertStringSidToSid(SDDL_ML_LOW, &plntegritySicl)) {        return FALSE;    }    BOOL bRes = FALSE;    if (OpenProcessToken(hProcess, MAXIMUM_ALLOWED, &hToken)) {        if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hTokenNew)) {            tml.Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;            tml.Label.Sid = plntegritySicl;            if (SetTokenInformation(hTokenNew, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(plntegritySicl))) {                if (CreateProcessAsUser(hTokenNew, NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &procInfo)) {                    bRes = TRUE;                }                if (bWait) {                    WaitForSingleObject(procInfo.hProcess, 10 * 1000);                }            }            CloseHandle(hTokenNew);        }        CloseHandle(hToken);    }    return bRes;}

4) 在IE7及以後,cookie引入了一個屬性HTTPONLY,值為0x2000。該標誌是一個安全性標誌,如果一個COOKIE欄位具有該屬性(標誌位具有0x2000這一位),則網頁尾本無法獲取該欄位,此欄位只存在於http請求的HEADER中。而對於客戶端,則有:IE6或IE7環境下:客戶端無法通過InternetGetCookie獲取此欄位值,只能讀取COOKIE文字,然後手動解析(參考第一部分:COOKIE檔案格式)。IE8環境下:客戶端可以通過InternetGetCookieEx,且引數dwFlags包含0x2000,來獲取此欄位值。