用ISAPI Filter設定HttpOnly屬性

2021-09-21 12:30:46 字數 4252 閱讀 5420

說到isapi很多人會覺得很陌生,因為如果你是做asp.net開發的話,isapi的方式已經過時,取而代之的是httphandler和httpmodule,說到這兩個東西很多人估計明白了,isapi可以說是早期實現請求攔截和處理的唯一途徑,只是隨著asp.net的流行,漸漸淡出了開發人員的視野。

此文的開發場景是這樣的,我們公司使用古老的asp語言,但是asp的response.cookies屬性中沒有httponly(但.net的cookie物件是有httponly屬性的),有帖子說可以利用path屬性來設定httponly,可以這麼做是因為我們在頁面中設定cookie值的動作都會被轉換成set-cookie頭,如下

set-cookie: user=t=bfabf0b1c1133a822; path=/
但如果要讓cookie變成httponly,就需要用如下格式:
set-cookie: user=t=bfabf0b1c1133a822; path=/;httponly
理論上講設定path是完全可行的,因為說白了就是在原來path的基礎上增加;httponly,

但經試驗表明這行不通,比如我用下面的**

得到的結果卻是

這顯然是不行的,所以我們不得不考慮用isapi來實現。

isapi基礎

首先,請不要把isapi extension和isapi filter混為一談,這兩個東西雖然只差乙個字,但卻完全是兩樣東西,所提供的介面是完全不一樣的。isapi extension是乙個類似頁面的dll,你可以對它做post或get提交,如http://localhost/abc.dll?a=1,從嚴格意義上講它沒有攔截的功能,和cgi差不多。而isapi filter則是具有過濾功能的,你可以在iis**的屬性中新增需要載入的isapi filter,例如asp.net的實現也使用了乙個isapi filter,叫做aspnet_filter.dll。

isapi filter說到底就是乙個dll,它有兩個主要的介面:getfilterversion和httpfilterproc,如下所示:

getfilterversion不僅僅是用來獲得filter版本這麼簡單,它可以用來過濾需要觸發的事件,這些事件的詳細資訊你可以參考請注意,這裡做的是或操作,而不是與操作,學過數理邏輯的應該明白這個是幹嘛用的,就是值的疊加,說的再直接點,eventa|eventb就是我既要event a也要event b。

httpfilterproc是主要入口,相當於console程式中的main。上面這段**是在這些事件觸發時寫入乙個日誌,這樣便於除錯。

說到這裡我們來了解下通常開發乙個isapi filter的流程。

a. 獲得乙個現有的isapi filter專案,當做模板,這個網上很多,google一下就有了。

b. 修改getfilterversion中的dwflags的值來決定需要哪些事件

c. 修改httpfilterproc中的case分支,刪除不需要的事件

d. 在需要處理的事件中寫**。

有一件事必須提醒大家,在寫isapi時,你千萬不要忘了把這兩個介面暴露出去,也就是定義dll的exports,如下:

事件的執行順序

在asp.net中我們有page life cycle,isapi filter也是如此,這些時間的執行順序可以在  上找到,下面的事件就是按執行順序排列的。

sf_notify_read_raw_data

sf_notify_preproc_headers

sf_notify_url_map 

sf_notify_authentication

sf_notify_auth_complete

sf_notify_send_response

sf_notify_send_raw_data

sf_notify_end_of_request

sf_notify_log

sf_notify_end_of_net_session

通過分析,我們知道要想獲得set-cookie header必須在asp把頁面處理完之後,因為asp頁面**有可能會設定cookie值,所以sf_notify_preproc_headers事件並不合適,因為它是在收到請求後,處理頁面前觸發的,我們需要的是在頁面處理完,傳送前觸發的事件,所以sf_notify_send_response最合適。在下一節我們將講解如何在該事件中新增處理**。

如何遍歷set-cookie

httpfilterproc函式的第三個引數void *pvdata是對應事件的資料,為了獲得header裡面的資料,我們會把它轉換成phttp_filter_preproc_headers,因為我們先要把set-cookie的資料讀出來,然後才能處理。

**如下:

這裡的szbuffer就是我們獲得的set-cookie的字串,這裡要講一下set-cookie到底是啥,因為很多程式設計師對set-cookie的含義和表示形式不是特別了解。

每次我們在頁面中設定cookie值,無論是asp還是asp.net,都會把設定的操作轉換為set-cookie中的一段字串,如果你使用fiddler或者httpfox跟蹤這些請求的話,你會發現頭裡面有一項就是set-cookie項,這項僅在有設定cookie的操作時才會有。另外,set-cookie中的每乙個cookie字串使用逗號分隔開的,如下

set-cookie: test1=a; path=/, test2=b; path=/

這裡設定了名為test1和test2的兩個cookie值,單個cookie的屬性之間使用分號分隔的。也正是因為如此,這段**中使用strtok來獲得字串中每一段用逗號分隔的cookie字串,這裡的cookienum表示set-cookie中cookie字串的總數(注意,不是字元的總數)。

一旦我們獲得了每乙個cookie的字串,我們就可以把;httponly附加到這些字串的最後,並最終把字串拼起來組成set-cookie字串,關於如何做字串拼接本文就不多講了,這完全是c++實現的問題。

如何覆蓋set-cookie字串

這裡的設定cookie和我們平時在**裡做的可不太一樣,因為我們要直接修改請求中的set-cookie,之所以是修改而不是增加新的set-cookie,是因為set-cookie在請求的header中只能有乙個,

上面的**把pvdata轉換成http_filter_send_response型別,這樣我們就可以對response進行操作,並通過呼叫它的setheader方法來設定set-cookie header。

ThreadLocal用開放定址法解決Hash衝突

1.鏈式位址法 2.開放定址法 3.再hash法 4.建立公共溢位池 等等為什麼不用3和4?4方法浪費記憶體,3增加了演算法的複雜度,不推薦。其實我也不清楚。鏈式位址法 hashmap 優點 處理衝突簡單,且無堆積現象,平均查詢長度短 鍊錶中的結點是動態申請的,適合構造表不能確定長度的情況 相對而言...

用棧設定密碼

include include include include define stack init size 10 define ok 1 define true 1 define false 0 define error 0 char password 10 abcdef 密碼,全域性變數 typ...

Javascript 用cssText設定樣式

一般情況下我們用js設定元素物件的樣式會使用這樣的形式 var element document.getelementbyid id element.style.width 20px element.style.height 20px element.style.border solid 1px r...