HTTP:超文本傳輸協議
允許將HTTP文檔從Web服務器傳送到客戶端的瀏覽器。HTTP請求報文分為3部分。第一部分叫做起始行(Request line)。第二部分叫首部(Request Header)。第三部分叫主題(Body)。
Response一樣,響應行(Response line),首部,主體。
Fiddle本質是一個代理服務器,代理地址127.0.0.1,端口;8888
GET /dongye95/home?wvr=5 HTTP/1.1
HTTP/1.1 200 OK
代理服務器
- 共享網絡
- 提高訪問速度,大部分代理服務器有緩沖功能
- 突破訪問限制
- 隱藏身份
Web通信安全
1.瀏覽器和Web服務器之間的內容應該只有瀏覽器和Web服務器能夠看到通信的真正內容。
2.HTTP請求的內容和HTTP請求的響應不會被第三方篡改。
Web服務器與每個客戶端使用不同的對稱加密算法。
HTTPS = HTTP + TLS 安全傳輸層協議或 SSL(Secure Sockets Layer 安全套接層)
HTTPS firefox 證書
包括IE、Chrome 和safari在內的大部分應用都使用Windows證書庫來驗證證書。firefox瀏覽器是自己維護證書列表,所以需要單獨安裝fiddle證書。
Tunnel to
HTTP Tunnel(也叫HTTP隧道,HTTP穿梭)是這樣一種技術。它用HTTP協議在要通信的 client 和 server 建立起一條 “Tunnel”。然后client 和server之間的通信都是在這條Tunnel的基礎上實現的。簡單來說,當Fiddle當做代理轉發HTTPS請求的時候,就會產生“CONNECT Tunnels”。
Fiddle可隱藏,Rules-》Hide CONNECTS
HTTP協議請求方法和狀態碼
HTTP 請求方法
GET | 請求指定的頁面信息並返回實體主體 |
HEAD | 類似於GET請求,只不過返回的響應中沒有具體的內容,用於獲取報頭 |
POST | 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中,post請求可能會導致新的資源的建立和/或對已有資源的修改 |
PUT | 從客戶端向服務端傳送的數據取代指定文檔的內容 |
DELETE | 請求服務器刪除指定的頁面 |
OPTIONS | 詢問支持的方法,用來查詢針對請求 URI 指定的資源支持的方法 |
TRACE | 追蹤路徑,讓 Web 服務器端將之前的請求通信環回給客戶端的方法 |
CONNECT | 要求用隧道協議連接代理,要求在與代理服務器通信時建立隧道,實現用隧道協議進行 TCP通信。 |
GET
用於獲取資源,常用於向服務器查詢某些信息。打開網頁一般都是用GET方法,因為要以Web服務器獲取信息。
參數
瀏覽器也可以在GET方法中把數據傳給服務器,數據放在URL的問號(?)后面,叫查詢字符串,也叫做Query String。查詢字符串以“名=值”這樣的形式出現,多個之間用“&”隔開
POST
通常用來把表單中填好的數據發送給服務器
GET和POST區別
- GET提交的數據會放在URL之后。POST放在Body中。
- GET提交的數據大小是有限制的(URL長度有限制)。POST沒有限制。
- GET方式提交數據會帶來安全問題,比如用戶名和密碼出現在URL中。頁面被緩存或其他人訪問這台機器,可從歷史記錄中獲得該用戶的賬號和密碼。
HTTP/1.1 狀態碼
狀態碼 | 已定義范圍 | 分類 |
1XX | 100 - 101 | 信息提示表示請求已被成功接收,繼續處理 |
2XX | 200 - 206 | 成功表示請求已被成功接收、理解、接收 |
3XX | 300 - 302 | 重定向,要完成請求,必須進行更進一步的處理 |
4XX | 400 - 415 | 客戶端錯誤,請求有語法錯誤或請求無法實現 |
5XX | 500 - 505 | 服務器錯誤,服務器未能實現合法的請求 |
常見的狀態碼
名稱 | 釋義 |
200 | OK:服務器成功處理了請求(這個是我們見到最多的) |
301/302 | Moved Permanently(重定向):請求的URL已移走。Response中應該包含一個Location URL,說明資源現在所處的位置 |
304 | Not Modified(未修改):客戶的緩存資源是最新的,需要客戶端使用緩存 |
404 | Not Found:未找到資源 |
401 | 禁止訪問 |
501 | Internal Server Error:服務器遇到一個錯誤,使其無法對請求提供服務 |
200(OK)
表示該請求被成功地完成,所請求的資源成功地發送回客戶端。
204(No Content,沒有內容)
返回的HTTP響應中只有一些Header和一個狀態行,沒有實體的主體內容(沒有響應Body)
204 狀態碼作用如下:
- 在不獲取資源的情況下了解資源的情況(比如判斷其類型)、
- 通過查看HTTP響應中的狀態碼看某個對象是否存在
- 通過常看Header測試資源是否被修改
206(Partial Content,部分內容)
表示服務器已經成功處理了部分GET請求(只有發送GET方法的HTTP請求,Web服務器才可能返回206)
- FlashGet、迅雷或者HTTP下載工具都是使用206狀態碼來實現斷點續傳的
- 將一個大文檔分解為多個下載段同時下載,比如在線看視頻。
http://tv.sohu.com/20121011/n354681393.shtml
301(Moved Permanently)
表示請求的網頁已經永久性地轉移到另一個地址
如下情況需要用到301:
- 防止用戶輸錯域名。
- 網站更換域名。比如www.360buy.com改為www.jd.com
- 有多個權重不錯的域名,需要把所有的權重都傳遞到新域名上,這就需要301重定向了。如果不設置301,多個域名綁定在一個主機頭上,會被搜索引擎認為是兩個相同的站點,不利於網站的排名。綁定的域名越多,內容重復度也就越高,排名越低。
302(Found)
當我們訪問一個URL的時候,服務器要我們訪問另一個資源,這回收瀏覽器會繼續發一個HTTP,請求訪問新的資源。
比如為登陸狀態下,直接訪問需要登陸才能訪問的頁面,會被服務器返回302,跳轉到登陸頁面。
301和302區別
- 301表示舊地址的資源已經被永久的移除了(這個資源不可訪問了),搜索引擎會把權重算到新地址。
- 302表示舊地址的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址跳轉到新地址,搜索引擎會把權重算到舊地址。
304(Not Modified)
304狀態碼代表上次的文檔已經被緩存了,還可以繼續使用
如果不想使用本地緩存,用【Ctrl + F5】強制刷新
400(Bad Request)
表示客戶端請求有語法錯誤
401(Unauthorized)
狀態碼401是指未授權錯誤,有些網頁采用的是HTTP基本認證(Basic Authentication),需要在HTTP請求中帶上 Authentication Header,否則服務器會返回狀態碼401
403(Forbidden)
表示Web客戶端發送的請求被Web服務器拒絕了。如果想說明原因,可以在body中說明,但是這個狀態碼通常表示服務器不想說明拒絕原因
404(Not Found)
資源不存在。本來就不存在,或者被刪了,或者被牆了。
500(Internal Server Error)
服務器內部錯誤。比如代碼錯誤,數據庫連接語句出錯,空指針等。
503(Server Unavailable)
服務器暫不可用。由於服務器維護或者過載,服務器當前無法處理請求;這個狀況是臨時的,並且將在一段時間以后恢復。
HTTP協議Header介紹
Header翻譯成中文,叫“首部”或者“頭域”。
Header語法格式是:“key:value”,一行一個Header
Cache:緩存相關。如果本地有“已緩存的”副本,就可以從本地存儲設備而不是從原始服務器中提取這個文檔。
Accept:表示瀏覽器客戶端可以接受的媒體類型。
Accept:text/html,*/*;q=0.8 代表瀏覽器可以處理所有的類型。一般瀏覽器客戶端給Web服務器發送的都是這個。
Accept-Encoding:跟壓縮有關。Accept-Encoding: gzip, deflate, br
Accept-Language:瀏覽器聲明自己接受的語言。
User-Agent:瀏覽器用來告訴服務器,客戶端使用的操作系統及版本、CPU類型、瀏覽器及版本,瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。
Referer:用來讓服務器判斷來源頁面,即用戶是從哪個頁面來的。網站通常用其來統計用戶來源,看用戶是從搜索頁面來的,還是從其他網站鏈接來的,或是從書簽等訪問的,以便合理定義網站。
Referer有時也被用作防盜鏈,即下載時判斷來源地址是不是在網站域名之內,否則就不能下載或顯示。
Connection:從HTTP/1.1起,系統默認都開啟了Connection:Keep-Alive,保持連接特性
HTTP協議是基於TCP協議的。當一個網頁完全打開后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉;如果客戶端再次訪問這個服務器上的網頁,將會連續使用這一條已經建立的連接。
Keep-Alive不會永久保持連接,它有一個保持時間。
Host:這個Header是必需的,它的作用是指定被請求的主機和端口號。
Web網頁抓包和Fiddler修改包
打開一個網頁,瀏覽器需要發送很多個請求。
- 在瀏覽器輸入http://www.cnblogs.com
- 瀏覽器會發送第一個HTTP請求去獲取頁面布局的HTML,這個請求叫做“父請求”。然后服務器把HTTP響應發回給瀏覽器。
- 瀏覽器會分析HTTP響應中的HTML,然后發現HTML中引用了其他文件:比如圖片,CSS,JS,JSON。瀏覽器會自動再次發送很多HTTP請求,去獲取圖片,CSS文件或者JS文件。這些HTTP請求叫做“子請求”。
- 當所有自請求的響應都返回后,瀏覽器會把1個父請求加上多個子請求渲染出來。這樣就形成了一個頁面。
用Fiddler選擇子請求
先找到父請求,鼠標右鍵選擇Select -> Child Requests
用Fiddler選擇父請求
先找到子請求,鼠標右鍵選擇Select -> Parent Requests
用Fiddler選擇相同請求
選擇一個請求,鼠標右鍵選擇Select -> Duplicate Requests
簡單性能測試
- 子請求出現了404或者500之類的錯誤,會嚴重影響整個網頁的加載速度。
- 子請求的響應速度慢也會影響網頁加載的速度。
可以清楚看到每個HTTP請求的響應時間
修改HTTP請求單個斷點:bpu www.baidu.com。取消:bpu
修改HTTP響應單個斷點:bpafter www.baidu.com。取消 bpafter
HTTP協議中的緩存
HTTP中具有緩存功能的是瀏覽器緩存和代理服務器緩存。
HTTP緩存是指當Web請求抵達緩存時,如果本地有“已緩存的”副本,就可以從本地存儲設備而不是從原始服務器中提取這個文檔。
緩存優點
- 減少了冗余的數據傳輸,節省了傳輸時間
- 減少了服務器的負擔,大大提高了網站性能
- 加快了客戶端加載網頁的速度
Web服務器通過以下2種方式來判斷瀏覽器緩存是否最新
- 瀏覽器把緩存文件的最后修改時間通過Header“If-Modified-Since”告訴Web瀏覽器
- 瀏覽器把緩存文件的ETag通過Header“If-None-Match”告訴服務器
通過最后修改時間來判斷緩存新鮮度
瀏覽器可以通過緩存文件的修改時間來判斷緩存的新鮮度,具體的步驟如下:
- 如果瀏覽器客戶端想請求一個文檔,它首先檢查本地緩存,發現存在這個文檔的緩存,獲取緩存中文檔的最后修改時間,通過“If-Modified-Since”發送HTTP請求給Web服務器。
- Web服務器收到HTTP請求,將服務器的文檔修改時間(Last-Modified)跟HTTP請求Header中的If-Modified-Since相比較。如果時間是一樣的,說明緩存還是最新的。Web服務器將發送狀態碼304(Not Modified)給瀏覽器客戶端,告訴客戶端直接使用緩存里的版本。
HTTP請求中跟緩存相關的Header
名稱 | 釋義 |
Cache-Control:max-age=0 | 以秒為單位 |
If-Modified-Since:Mon,19 Nov 2012 08:38:01 GMT | 緩存文件的最后修改時間 |
If-None-Match:"0693f67a67cc1:0" | 緩存文件的ETag |
Cache-Control:no-cache | 不使用緩存 |
Pragma:no-cache | 不使用緩存 |
HTTP響應中跟緩存相關的Header
名稱 | 釋義 |
Cache-Control:public |
響應被緩存,並且在多用戶間共享 |
Cache-Control:private | 響應只能作為私有緩存,不能再用戶之間共享 |
Cache-Control:no-cache | 提醒瀏覽器要從服務器提取文檔進行驗證 |
Cache-Control:no-store | 絕對禁止緩存(用於機密、敏感文件) |
Cache-control:max-age=60 | 60s之后緩存過期(相對時間) |
Date:Mon,19 Nov 2012 08:39:00 GMT |
當前響應發送的時間 |
Expires:Mon,19 Nov 2012 08:40:01 GMT | 緩存過期的時間(絕對時間) |
Last-Modified:Mon,19 Nov 2012 08:38:01 GMT | 服務器端文件的最后修改時間 |
ETag:"20b1add7ec1sd1:0" |
服務器端文件的ETag值 |
如果同時存在cache-control和Expires怎么辦?瀏覽器總是優先使用cache-control。
ETag
是Entity Tag(實體標簽)的縮寫,是根據實體內容生成的一段hash字符串(類似於MD5或者SHA1之后的結果)
使用ETag主要是為了解決一些Last-Modified無法解決的問題。
- 某些服務器不能精確得到文件的最后修改時間,這樣就無法通過最后修改時間來判斷文件是否更新了。
- 某些文件的修改非常頻繁,在以秒為單位以下的時間內進行修改,而Last-Modified只能精確到秒
- 一些文件的最后修改時間改變了,但是內容並非改變,我們不希望客戶端認為這個文件修改了。
使用【Ctrl + F5】可以強制刷新瀏覽器,可以讓瀏覽器不使用緩存。
Pragma:no-cache的作用和“Cache-Control:no-cache”一模一樣,都是不使用緩存。Pragma:no-cache是HTTP1.0中定義的,所以為了兼容HTTP1.0會同時使用Pragma:no-cache和Cache-Control:no-cache
HTTP協議壓縮和URL Encode
HTTP采用通用的壓縮算法,比如用gzip來壓縮HTML、JavaScript、CSS文件,能大大減少網絡傳輸的數據量,提高了用戶顯示網頁的速度。當然,這同時也會增加一點點服務器的開銷。
HTTP壓縮的過程
- 瀏覽器發送HTTP請求給Web服務器,請求中的Header能Accept-Encoding:gzip,deflate(告訴服務器,瀏覽器支持gzip壓縮)
- Web服務器接到HTTP請求后,生成原始的HTTP響應,其中有原始的 Content-Type 和 Content-Length
- Web服務器通過gzip來對HTTP響應進行編碼,編碼后Header中有 Content-Type 和 Content-Length(壓縮后的大小),並且增加了Content-Encoding:gzip,然后把HTTP響應發送給瀏覽器。
- 瀏覽器接到HTTP響應后,根據Content-Encoding:gzip來對HTTP響應進行解碼,獲取到原始HTTP響應后顯示出網頁。
內容編碼類型:
Content-Encoding header 就是用這些標准化的代號來說明編碼時使用的算法
- gzip 表明實體采用 GNU zip 編碼
- compress 表明實體采用 UNIX的文件壓縮程序
- deflate 表明實體是用 zlib 的格式壓縮的
- identity 表明沒有對實體進行編碼;當沒有 Contetn-Encoding header 時,就默認為這種情況。
gzip、compress以及deflate編碼都是無損壓縮算法,用於減少傳輸報文的大小,不會導致信息損失。其中 gzip 通常效率最高,使用最為廣泛。
gzip是如何壓縮的
簡單來說,gzip壓縮實在一個文本文件中找出類似的字符串,並臨時替換它們,從而使整個文件變小。這種形式的壓縮對Web來說非常適合,因為HTML和CSS文件通常包含大量重復的字符串,例如空格、標簽等。也正是因為這樣,gzip對JPEG這類文件壓縮效果不好。
HTTP內容編碼和HTTP壓縮的區別
用其他編碼方式把內容攪亂或者加密,以此來防止未被授權的第三方開到文檔的內容。所以,我們說HTTP壓縮其實就是HTTP內容編碼的一種。
URL Encode介紹
URL只能用英文字母、數字或者某些標點符號,不能使用其他文字和符號。
URL Encode(URL編碼)就是把所有非英文字母、數字字符都替換成百分號(%)后加兩位十六進制數。
比如在搜狗搜索里輸入中文,點擊查找
中文對應為%E4%B8%AD%E6%96%87
在Fiddler中可以使用TextWizard工具來進行轉換
Fiddler使用技巧
1.【Ctrl + X】清空列表
2.Fiddler異常退出后無法上網,重新啟動Fiddler然后再關閉。
3.Fiddler中查詢對話,【Ctrl + F】就可以了。
4.Fiddler中保存抓到的包
先選中session,然后右鍵 -> Save -> Selected Sessions。保存后的文件后綴名是.saz。文件會保存完整的HTTP請求和HTTP響應
雙擊.saz文件,或者單機Fiddler菜單欄中的File -> Load Archive,就能打開.saz文件。
Fiddler常用快捷鍵
快捷鍵 | 用途 |
Ctrl + X | 刪除所有的Session |
Ctrl + A | 選擇所有的Session |
ESC | 不選擇任何的Session |
Ctrl + I | 反選Session |
Delete | 刪除選擇的Session |
Shift + Delete | 刪除未選擇的Session |
R | 重放選擇的Session(可以重放多個Session) |
Shift + R | 多次重放選擇的Session(隨后會提示你輸入,重放幾次) |
U | 無條件的重放選擇的Session(不會發送If-Modified-Since 和 If-None-Match-Headers) |
Shift + U |
無條件的重放選擇的Session(隨后會提示你輸入,重放幾次) |
P | 選擇“當前Session”的“父Session”(這個功能取決於Referer Header) |
C | 選擇“當前Session”的“子Session” |
D | 選擇“重復的Session”(有相同的URL和相同的method) |
BackSpace或鼠標上的“Back” | 選擇“上次選擇的Session” |
Insert | |
Ctrl + 1 Ctrl + 2 Ctrl + 3 Ctrl + 4 Ctrl + 5 Ctrl + 6 |
用粗體和顏色標記選擇的Session |
M | 給選擇的Session添加注釋 |
Fiddler插件
Fiddler插件下載地址:www.telerik.com/fiddler/add-ons
比較會話的不同:Windiff
格式化JS代碼:JavaScript Formatter
圖片縮略圖:Gallery
Fiddler的Script用法
Fiddler Script是一個可以自動修改HTTP請求和HTTP響應的腳本文件,使你不用手動地去下“斷點”來修改。
Fiddler Script的本質其實是用JScript.NET語言寫的一個腳本文件CustomRules.js,其語法類似於C#。
Fiddler Script Editor
或者
CustomRules.js中的主要方法
static function OnBeforeRequest(oSession:Session)
OnBeforeRequest函數在每次請求之前調用。在這個方法中修改Request的內容,我們用的最多
static function OnBeforeResponse(oSession:Session)
OnBeforeResponse函數在每次響應之前調用,在這個方法中修改Response的內容。
static function OnExexAction(sParams:String[])
這個方法中包含Fiddler命令。命令是在Fiddler界面中左下方的QuickExec中執行的。
Fiddler定制菜單
Rules -> User-Agents菜單中好像沒有Iphone-4S safari,我們現在可以定制一個。上網查詢user-Agents,添加代碼:
RulesStringValue(23,"Iphone 4S safari","Mozilla/5.0(iPhone;U;CPU iPhone OS 4_0 like Mac OS X;en-us)AppleWebKit/532.9(KHTML,like Gecko) Version/4.0.5 Mobile/8A293Safari/6531.22.7")
重啟Fiddler就行
修改Session在Fiddler的顯示樣式
把以下腳本放在OnBeforeRequest(oSession:Session)方法下,並且單機“Save script”,這樣所有的cnblogs會話都會顯示為紅色
if (oSession.HostnameIs("www.cnblogs.com")) { oSession["ui-color"] = "red" }
修改HTTP請求
如果要修改HTTP請求,代碼應該放在OnBeforeRequest(oSession:Session)方法下面。
我們可以修改HTTP請求中的任何數據,如HOST、Header、Cookie等
修改HTTP請求中的Cookie
if(oSession.uriContains("cnblogs.com") { //1.刪除所有的cookie oSession.oRequest.headers.Remove("Cookie"); //2.新建cookie oSession.oRequest.headers.Add("Cookie","username=testname;testpassword=P@ssword1"); //修改Cookie,不能刪除或者編輯單獨的一個Cookie,需要替換Cookie字符串 var oldCookie = oSession.oRequest["Cookie"]; oldCookie = oldCookie.Replace("cookieName=","ignoreme=") oSession.oRequest["Cookie"] = oldCookie; //4.全新的Cookie var newCookie = "your cookie String"; oSession.oRequest["Cookie"] = newCookie; }
替換HTTP請求的Host地址
我們最初發送給A站點的HTTP請求,都被Fiddler轉發到B站點,而在瀏覽器中毫無感覺。測試或者debug過程中經常會有這種需求。
例如用 www.sina.com 代替 www.baidu.com
if (oSession.HostnameIs("www.sina.com")) { oSession.hostname = "www.baidu.com"; }
修改HTTP請求中的Header
if (oSession.uriContains("cnblogs.com")) { // 添加Header oSession.oRequest.headers.Add("headerName1","headerValue1"); // 刪除Header oSession.oRequest.headers.Remove("headerName2"); // 修改Header oSession.oRequest["Referer"] = "www.baidu.com/TestReferer"; }
修改HTTP請求中發的Body
方法一:先把Body的字符串讀取出來,修改后再塞回去。
static function OnBeforeRequest(oSession:Session) { if (oSession.uriContains("http://www.cnblogs.com/TankXiao/")) { oSession.utilDecodeRequest(); // 獲取Request中的body字符串 var strBody=oSession.GetRequestBodyAsString(); // 用正則表達式或者 replace 方法修改string strBody=strBody.replace("1111","2222"); // 彈個對話框檢查下修改后的body FiddlerObject.alert(strBody); // 將修改后的body,重新寫會Request中 oSession.utilSeRequestBody(strBody); } }
第二種方法:也可以采用非常簡單地方法,即直接替換body中的數據
if (oSession.uriContains("cnblogs.com")) { oSession.utilReplaceInRequest("1111","2222"); }
修改HTTP響應
在Script中修改HTTP響應的方法,代碼應該放在OnBefroeResponse(oSession:Session)方法下面。
修改HTTP響應的方法和修改HTTP請求的方法差不多。
實例:使用如下代碼,修改博客園網頁中的數據
if (oSession.uriContains("cnblogs.com")) { oSession.utiReplaceInResponse("小坦克","大坦克 肖佳"); }
打開瀏覽器,輸入 www.cnblogs.com/tankxiao/
讀寫txt文件
先引用命名空間
import System。IO; // Read var txtPath = "c:\\tank.txt" var allNumbers = File.ReadAllLines(txtPath); var exist = 0; for(var i = 0; i<allNumbers.length;i++) { FiddlerObject.alert(allNumbers[i]); } // write var txtPath = "c:\\tank.txt" var txtWrite = File.AppendText(textPath); txtWriteLine("www.cnblogs.com/tankxiao"); txtWrite.Close();
使用正則表達式
先引用命名空間
import System.Text.RegularExpressions; var resBody = "<String>tankxiao.cnblogs.com</string>"; var r = new Regex("<string>(.*?)</string>"); var mc = r.Match(resBody); FiddlerObject.alert(mc.Groups[1].Value);
保存Session
var sazFile = "c:\\aff\\"+number; var sessionList : Session[] = [oSession]; Utilities.WriteSessionArchive(sazFile,sessionList,null,true)
讀取Session,並且使用Fiddler來發送
var sazFile="c:\\aff\\"+number; var sessionList : Session[] = Utilities.ReadSessionArchive(sazFile,true); FiddlerApplication.oProxy.SendRequest(sessionList[0].oRequest.headers,sessionList[0].requestBodyBytes,null);
深入理解Cookie機制
HTTP協議是無狀態的
對於瀏覽器的每一次請求,服務器都會獨立處理。不與之前或之后的請求發生關聯。即使同一個瀏覽器發送了3個請求,服務器也會獨立處理這3個請求,服務器並不知道這3個請求是來自同一個瀏覽器。
服務器需要識別瀏覽器請求,就必須弄清楚瀏覽器的請求狀態。既然HTTP協議是無狀態的,那就讓服務器和瀏覽器共同維護一個狀態,這就是會話機制。
會話機制
瀏覽器第一次請求服務器時,服務器創建一個會話,並將會話的id作為響應的一部分發送給瀏覽器。
瀏覽器存儲會話id,並在后續第二次和第三次請求中帶上會話id。服務器取得請求中的會話id就知道是不是同一個用戶了。
Cookie機制
服務器在內存中保存會話對象。瀏覽器可以使用Cookie機制保存會話id。
Cookie機制是一種會話機制。Cookie是瀏覽器用來存儲少量數據的一種機制,數據以“key=value”形式存儲,瀏覽器發送HTTP請求時,自動附帶cookie信息。
Cookie是什么
Cookie是一小段文本信息,伴隨着用戶請求和頁面在瀏覽器和Web服務器之間傳遞。
Cookie是一種HTTP Header,以“key=value”的形式組成,比如ip_country=CN
兩個Cookie之間用分號隔開,比如ip_country=CN;mbox=check#true#1499311989
瀏覽器把Cookie通過HTTP請求中的Header,比如“Cookie:ip_country=CN”發送給Web服務器。Web服務器通過HTTP響應中的Header,比如“Set-Cookie:ip_country=CN”,把Cookie發送給瀏覽器。
Cookie的作用
Cookie最主要的作用是用來做用戶認證,還可以用於保存用戶的一些其他信息。
Cookie也可以用於互聯網精確廣告定向技術,比如用戶瀏覽了某些商品,就可以用Cookie將其記錄下來。
Cookie的屬性
從Fiddler的抓包中,我們可以看到Web服務器返回了下面這一段數據給瀏覽器。
Set-Cookie:cookie_user_token=C5CBD6FBDJO5HGH324OV452;Expires=Thu,06-Jul-2017 09:17:46 GMT;Path=/;HttpOnly
Expires屬性:Expires的值是一個時間,代表過期時間。過了這個時間,該Cookie就失效了。如果不指定Expire time,表示關閉瀏覽器/頁面的時候,此Cookie就應該被瀏覽器刪除了。
Path屬性:表示Cookie所屬的路徑,asp.net默認為“/”,就是根目錄。在同一個服務器上的目錄如下:/test/、/test/cd/、/test/dd/。現假設一個Cookie1的path為/test/,Cookie2的path為/test/cd/,那么test下的所有頁面都可以訪問到Cookie1,而/test/cd/的子頁面不能訪問Cookie2。
HttpOnly屬性:這是個關於安全方面的屬性,將一個Cookie設置為HttpOnly后,通過JavaScript腳本將無法讀取到Cookie信息,這能有效地防止黑客用XSS發起攻擊。一般來說,跟登陸相關的Cookie必須設置為HttpOnly。
Cookie的分類
會話Cooike:臨時地Cookie,它記錄了用戶訪問站點時的設置和偏好;關閉瀏覽器,會話Cookie就被刪除了
持久Cookie:存儲在硬盤上,不管瀏覽器退出或者計算機重啟,持久cookie都繼續存在,持久Cookie有過期時間。
網站自動登錄的原理
在登錄頁面輸入用戶名、密碼,選擇保存密碼單機登錄(這時候,其實在你的機器上已保存好了登錄的Cookie),下次訪問的時候。
- 用戶打開IE瀏覽器,在地址欄輸入www.cnblogs.com
- IE首先會在硬盤中查找關於cnblogs.comde Cookie,然后把Cookie放到HTTP Request中,再把Request發給Web服務器。
- Web服務器返回博客園首頁,這時你會看到自己已經登錄了。
Fiddler實現Cookie劫持攻擊
通常有兩種方法可以截獲他人的Cookie
- 通過跨站腳本攻擊(XSS)獲取他人的Cookie。
- 想辦法獲取別人電腦上保存的Cookie文件。
找到登錄的Cookie
首先,我們需要使用 Fiddler 找到跟登錄相關的 Cookie,具體的操作步驟如下。
打開豆瓣網 www.douban.com,用賬號和密碼登錄。
啟動Fiddler,在豆瓣網中單擊右上角的用戶名,在菜單欄中單機“賬號管理”,就跳轉到了這個頁面:https://www.douban.com/accounts/。
在Fiddler中選擇https://www.douban.com/accounts/這個Session,然后用鼠標右鍵選擇Replay -> Reissue and Edit。在Raw選項卡下,找到一個名叫dbcl2的Cookie,比如我這里的是:dbcl2=“163572032:csUO41kxRDg”;刪除這個 dbcl2 的Cookie,然后單機“Run to Completion”放行。
我們可以發現跳轉到了登錄頁面。這說明dbcl2這個Cookie是跟登錄相關的,將其刪除后就處於未登錄狀態,Web服務器會返回302狀態碼,會自動重定向到登錄界面。
網站退出的作用
網站退出是明確地告訴服務器立即刪除服務器端的Session對象,這樣客戶端登錄的Cookie就失效了。如果用戶登錄某個網站,然后離開的時候直接關閉瀏覽器,那么登錄的Cookie還在,存在被冒用的風險。保險的辦法是單擊退出而不是直接關閉瀏覽器。
HTTP基本認證
HTTP協議是無狀態的,瀏覽器和Web服務器之間可以通過Cookie來識別身份。一些桌面應用程序(比如新浪桌面客戶端)跟Web服務器之間是如何識別身份呢?
HTTP協議中還有兩種認證方式,分別是基本認證和摘要認證。認證就是客戶端要給服務器出示一些自己的身份證明,來證明自己是誰,一旦服務器知道了客戶端的身份,就可以判定客戶端可以進行訪問了。通常是通過提供用戶名和密碼來進行認證的。
什么是HTTP基本認證
一些網站和Web服務使用的是HTTP基本認證。有些桌面應用程序也通過HTTP協議跟Web服務器交互,桌面應用程序一般不會使用Cookie,而是把“用戶名+冒號+密碼”用Base64編碼放在HTTP請求中的 Header Authorization 中發送給服務器,這種方式叫HTTP基本認證(Basic Authentication)。
在基本認證中,Web服務器可以拒絕一個事物,要求客戶端提供有效地用戶名和密碼。服務器會返回401狀態碼來初始化認證質詢,並用WWW-Authenticate響應首部指定要訪問的安全域。瀏覽器收到質詢時,會打開一個對話框,請求用戶輸入用戶名和密碼,然后將用戶名和密碼用Base64編碼,再用 Authorization 請求首部發送給服務器。
在Fiddler中可以在Inspectors中的Auth選項卡中查看實際用戶名和密碼。
HTTP基本認證的缺點
把“用戶名+冒號+密碼”用Base64編碼,可逆,所以不能用HTTP在網絡上傳輸,一定要用HTTPS傳輸,因為HTTPS是加密的,稍微安全一點。
- HTTP協議是無狀態的,同一個客戶端對服務器的每個請求都要求認證。
- 基本認證會通過網絡發送用戶名和密碼,這些用戶名和密碼以Base64編碼。Base64編碼是一種可逆編碼,容易被第三方攔截。
- 使用基本認證登錄后,除非關閉瀏覽器或者清楚歷史記錄,否則將無法登出。
- 無法防止重放攻擊。即使基本認證的密碼是經過加密傳輸的,第三方仍然可以捕獲被修改過的用戶名和密碼,並將修改過的用戶名和密碼反復多次地重放給原始服務器,以獲得對服務器的訪問權,基本認證沒有什么措施可以防止這些重放攻擊。
摘要認證
摘要認證是針對基本認證存在的諸多問題而進行改良的方案。摘要認證是另外一種HTTP認證協議,它試圖修復基本認證的嚴重缺陷,進行如下改進。
- 通過傳遞用戶名、密碼等計算出來的摘要來解決以明文方式在網絡上發送密碼的問題。
- 通過服務器產生隨機數 nonce 的方式防止惡意用戶捕獲並重放認證的握手過程。
- 通過客戶端產生隨機數 cnonce 的方式支持客戶端對服務器的認證。
- 通過對內容也加入摘要計算的方式,可以有選擇地防止對報文內容的篡改。
Fiddler發送HTTP請求
Fiddler可以使用重放功能或者Fiddler Composer來發送HTTP請求。
Fiddler Composer發送HTTP請求
Fiddler有個功能組件叫Composer,可以用來發送HTTP請求。Fiddler的作者把HTTP Request發送器取名為Composer,中文意思是樂曲的創造者,很有詩意。
Composer發送Get請求
Composer的編輯模式
Composer有兩種編輯模式
- Parsed模式。這個模式比較常用,把HTTP請求分為3個部分:請求起始行,請求Header和請求Body。通過該模式,創建一個HTTP請求變得很容易。
- Raw模式。該模式需要一行一行地寫一個HTTP請求。
Composer發送Post請求
禪道的演示網站 http://demo.zendao.net,用戶名是demo,密碼是123456。手動登錄抓包如下:
用Fiddler發送一個登錄的Post請求
Composer編輯之前捕獲的HTTP請求
在Web會話列表中,可以將捕獲到的HTTP請求拖拽到Composer中,編輯后再發送出去。
Fiddler重新發送HTTP請求
Fiddler可以將捕獲的HTTP請求重新發送出去。Fiddler工具欄上有一個Replay按鈕,單擊該按鈕可以向Web服務器重新發送選中的HTTP請求。當選中多個Session,並且按下Replay按鈕后,Fiddler會用多線程同時發送請求。此功能可以用來做並發性能測試。
Replay菜單
按下Shift鍵的同時單擊該按鈕,會彈出提示框,要求指定每個請求被重新發送的次數。
按下Ctrl鍵的同時單擊該按鈕,在HTTP請求中不會包含IF-Modified-Since和If-None-Match。
在會話列表中,選中一個或者多個Session,右鍵菜單我們可以看到一個Replay菜單。
Reissue Requests | 重新發送請求,和菜單欄上Replay按鈕是一樣的功能 |
Reissue Unconditionally | 無條件反復發送選中的請求 |
Reissue and Edit | 把選中的請求以原來的形式重新發送,在每個新的Session中設置斷點,在請求發送給服務器之前,可以修改請求 |
Reissue and Verify | 重新發送請求,檢查響應,如果響應和上一個請求一樣,就會變成綠色 |
Reissue Sequentially | 選中多個Session會按順序一個一個重新發送請求,是單線程模式 |
Reissue from Composer | 在Composer中編輯該請求 |
Revisit in IE | 在IE瀏覽器中用Get方法訪問這個請求 |
簡單地性能測試
在Web Sessions列表中,選中一個或者多個Session,然后按下Shift鍵的同時單擊“Replay”按鈕,會彈出提示框,要求指定每個請求被重新發送的次數。Fiddler會用多線程同時發送該請求,相當於模擬了很多用戶同時訪問該請求。
先編輯再發送
在Web Sessions列表中,選中一個Session,單擊鼠標右鍵選擇Replay - Reissue and Edit。該功能可以把一個HTTP請求重新發送出去,並且攔截住,將其進行編輯,然后再發出去。
安全測試之重放攻擊
重放攻擊(Replay Attacks)又稱重播攻擊、回放攻擊。
攻擊者發送一個目的主機已接收過的包,特別是在認證的過程中,用於認證用戶身份所接收的包,來達到欺騙系統的目的。該包主要用於身份認證過程,破壞認證的安全性。
重放攻擊是怎么發生的
重放攻擊是指黑客通過抓包的方式,得到客戶端的請求數據及請求連接,重復地向服務器發送請求的行為。
重放攻擊的危害
比如APP中有一個“下單”的操作,當你單擊購買按鈕時,APP向服務器發送購買的請求。而這時黑客對你的請求進行了抓包,得到了你的傳輸數據,黑客把數據再往服務器提交一次。這就導致了你可能只想購買一個產品,結果由於黑客重放攻擊,你就購買了多次。
很多網站的投票或者點贊功能也要防止重放。黑客會對投票或者點贊進行抓包,然后重復發送來進行刷票。
重放攻擊的解決方案
在HTTP請求中添加時間戳(stamp)和數字簽名(sign),可以防止重放攻擊。
數字簽名是為了確保請求的有效性。因為簽名是經過加密的,只有客戶端和服務器知道加密方式及Key,第三方模擬不了。
時間戳是為了確保請求的時效性。我們將上一次請求的時間戳進行存儲。
Fiddler實現弱網測試
網速慢和網絡中斷的情況,我們稱之為弱網。
使用Fiddler能讓弱網測試變得非常簡單,Fiddler是通過延遲發送或接收數據的時間來模擬限速的。
什么是弱網
驗證在弱網的情況下軟件的處理機制,從而避免因用戶體驗不友好造成用戶的流失。弱網測試屬於健壯性測試。在弱網測試條件下,要測試產品的運行狀態、處理機制、提示信息,以及網絡恢復后的重連等。
弱網環境帶來的問題
1、操作時間慢。用戶在地鐵里操作手機APP,由於網絡慢,頁面加載不出來。原因可能是API在網絡慢的情況下性能很差。用戶在公交車上用手機APP看新聞,當公交車進入隧道的時候,網絡變得很慢,APP上的新聞一直沒法加載出來。我們需要測試每個API消耗的時間,這個指標可以衡量APP性能的好壞。
2、用戶體驗不好。一個安卓手機用戶使用一款看小說的APP在地鐵里看小說,當地鐵進入隧道的時候,手機信號中斷了。用戶單擊翻頁,想看下一頁的時候,因為網絡中斷,APP的界面卡死並且閃退。原因是APP不穩定,沒有處理好網絡中斷的情況。
3、非正常情況下,出現Bug的可能性會增加。如一個電商的手機APP有秒殺優惠券的功能。一些APP用戶在乘坐電梯的時候,使用APP來秒殺優惠券。單擊秒殺優惠券的按鈕后,APP響應緩慢。於是,用戶重復單擊秒殺優惠券按鈕。這就造成了幾乎同一時間,同一個用戶有多個HTTP請求發送服務器,形成了並發,結果用戶搶到了多張優惠券。
弱網測試的目的
弱網測試的目的是讓APP在任何網絡下都能表現自如,讓開發人員能夠預知APP在較差網絡環境下的表現,提前發現問題,進行有針對性的優化
弱網的場景
1、網絡慢或者延遲,導致加載時間長。
2、網絡中斷,Web服務器返回500等狀態碼。
3、網絡超時,HTTP請求發出去后,很久都沒有響應。
Fiddler模擬網絡延遲
1、啟動Fiddler,選擇Rules - Performances - Simulate Modem Speeds
2、打開瀏覽器,訪問網站。
精確控制網速
可參考:https://www.jianshu.com/p/b9e349b8f411
1、啟動Fiddler,選擇Rules - Performances - Simulate Modem Speeds
2、在FiddlerScript中找到如下一段代碼
if (m_SimulateModem) { // Delay sends by 300ms per KB uploaded. 每上傳1KB數據,延時0.3秒 oSession["request-trickle-delay"] = "300"; // Delay receives by 150ms per KB downloaded. 每下載1KB數據,延時0.15秒 oSession["response-trickle-delay"] = "150"; }
改動數值,保存Script即可。
3、保存完之后,原本已經勾選的Simulate Modem Speeds會被取消勾選:再次選中 Rules - Performances - Simulate Modem Speeds
4、再次打開瀏覽器,訪問網頁
如果你習慣用kbps 去算的話,那么我們的算法就是 1KB/下載速度 = 需要delay的時間(毫秒),比如50KBps 需要delay20毫秒來接收數據。
request-trickle-delay中的值代表每KB的數據被上傳時會被延時多少毫秒;response-trickle-delay則對應下載時每KB的數據會被延時多少毫秒。 比如你要模擬上傳速度100KBps的網絡,那上傳延遲就是1KB/100KBps=0.01s=10ms,就改成10。
比如默認設置下上傳延時為300ms下載延時為150ms,可以推算出大致的模擬帶寬為:
下載帶寬 = 1KB/150ms = (1 * 8/1000) /0.150 ≈ 0.053Mbps
(1MB = 1024 KB ≈ 1000 KB 這里為了運算簡便就用了1000的倍數,忽略誤差)
方法二,下面的腳本實現了一個隨機延時量設置,使得網絡帶寬不是恆定為一個低速的值,而是會在一定范圍內隨機抖動:
if (m_SimulateModem) { // Delay sends by 300ms per KB uploaded. oSession["request-trickle-delay"] = ""+randInt(1,50); // Delay receives by 150ms per KB downloaded. oSession["response-trickle-delay"] = ""+randInt(1,50); }
方法三:
點擊fiddlerScript 在代碼里找到onBeforeRequest,這里定義了在發送請求前做什么。加入如下代碼可以實現延遲:
oSession["request-trickle-delay"]="3000"; //請求階段延遲3秒 oSession["response-trickle-delay"]="3000"; //響應階段延遲3秒
Fiddler模擬網絡中斷
用Fiddler可以下斷點,偽造HTTP響應。移動端發出的HTTP請求根本沒有到達服務器,而是被Fiddler直接返回了一個偽造的HTTP響應。
具體做法是用Fiddler攔截住移動端發出來的HTTP請求,然后在“Choose Response”選中需要返回的狀態碼並返回給移動客戶端。
或者可以在桌面新建一個txt文檔:
HTTP/1.1 500 Internal Server Error Date: Fri, 11 Aug 2019 07:25:35 GMT Content-Type: text/html; charset=utf-8 Connection: keep-alive Vary: Accept-Encoding this is 500 internal Server Error by Fiddler! tank
Fiddler模擬網絡超時
利用Fiddler下斷點的功能攔截移動客戶端發出的HTTP請求,這樣就相當於網絡超時了,然后再檢查客戶端有沒有重發或者超時的機制。