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请求,这样就相当于网络超时了,然后再检查客户端有没有重发或者超时的机制。