您的位置:首页 > 理论基础 > 计算机网络

理解HTTP消息头【很完整,例子也很丰富】 续

2010-03-02 09:32 330 查看

理解HTTP消息头 (三)

(三) 客户端发送的内容
这一次主要来观察HTTP消息头中客户端的请求,从中找到一些有意思的内容。
 
1 HTTP_REFERER
写两个简单的网页:
a.htm:
<a href=b.htm>to page b</a>
b.htm:
haha
内容很简单,就是网页A中有一个到B的链接。把它们放到IIS上,并访问网页A,从中再点击到B的链接,于是看到了B页的“haha”。那么这两次请求有什么不同吗?观察它们所发送的HTTP消息头,最明显的区别就是访问B页时比访问A页时多了一行:
Referer: http://localhost/a.htm
这一行就表示,用户要访问的B页是从A页链接过来的。
服务器端要想取得这个值也是很容易的,以ASP为例,只需要写一句
<% =Request.ServerVariables("HTTP_REFERER") %>
就可以了。
一些网站通过HTTP_REFERER来做安全验证,判断用户是不是从允许的页面链接来的,而不是直接从浏览器上打URL或从其他页面链接过来,这样可以从一定程度上防止网页被做非法使用。但从上述原理来看,想要骗过服务器也并不困难,只要手工构造输入的HTTP消息头就可以了,其他常用的手段还有通过HOSTS文件伪造域名等。
除了超链接以外,还有其他几种方式会导致HTTP_REFERER信息被发送,如:
内联框架:<iframe src=b.asp></iframe>
框架集:<frameset><frame src=b.asp></frameset>
表单提交:<form action=b.asp><input type=submit></form>
SCRIPT引用:<script src=b.asp></script>
CSS引用:<link rel=stylesheet type=text/css href=b.asp>
XML数据岛:<xml src=b.asp></xml>
而以下形式不会发送HTTP_REFERER:
script转向:<script>location.href="b.asp"</script>
script开新窗口:<script>window.open("b.asp");</script>
META转向:<meta http-equiv="refresh" content="0;URL=b.asp">
引入图片:<img src=b.asp>
 
2 COOKIE
COOKIE是大家都非常熟悉的了,通过它可以在客户端保存用户状态,即使用户关闭浏览器也能继续保存。那么客户端与服务器端是如何交换COOKIE信息的呢?没错,也是通过HTTP消息头。
首先写一个简单的ASP网页:
<%
Dim i
i =  Request.Cookies("key")
Response.Write i
Response.Cookies("key") = "haha"
Response.Cookies("key").Expires = #2007-1-1#
%>
第一次访问此网页时,屏幕上一片白,第二次访问时,则会显示出“haha”。通过阅读程序不难发现,屏幕上显示的内容实际上是COOKIE的内容,而第一次访问时还没有设置COOKIE的值,所以不会有显示,第二次显示的是第一次设置的值。那么对应的HTTP消息头应该是什么样的呢?
第一次请求时没什么不同,略过
第一次返回时消息内容多了下面这一行:
Set-Cookie: key=haha; expires=Sun, 31-Dec-2006 16:00:00 GMT; path=/
很明显,key=haha表示键名为“key”的COOKIE的值为“haha”,后面是这则COOKIE的过期时间,因为我用的中文操作系统的时区是东八区,2007年1月1日0点对应的GMT时间就是2006年12月31日16点。
第二次再访问此网页时,发送的内容多了如下一行:
Cookie: key=haha
它的内容就是刚才设的COOKIE的内容。可见,客户端在从服务器端得到COOKIE值以后就保存在硬盘上,再次访问时就会把它发送到服务器。发送时并没有发送过期时间,因为服务器对过期时间并不关心,当COOKIE过期后浏览器就不会再发送它了。
如果使用IE6.0浏览器并且禁用COOKIE功能,可以发现服务器端的set-cookie还是有的,但客户端并不会接受它,也不会发送它。有些网站,特别是在线投票网站通过记录COOKIE防止用户重复投票,破解很简单,只要用IE6浏览器并禁用COOKIE就可以了。也有的网站通过COOKIE值为某值来判断用户是否合法,这种判断也非常容易通过手工构造HTTP消息头来欺骗,当然用HOSTS的方式也是可以欺骗的。
 
3 SESSION
HTTP协议本身是无状态的,服务器和客户端都不保证用户访问期间连接会一直保持,事实上保持连接是HTTP1.1才有的新内容,当客户端发送的消息头中有“Connection: Keep-Alive”时表示客户端浏览器支持保持连接的工作方式,但这个连接也会在一段时间没有请求后自动断开,以节省服务器资源。为了在服务器端维持用户状态,SESSION就被发明出来了,现在各主流的动态网页制做工具都支持SESSION,但支持的方式不完全相同,以下皆以ASP为例。
当用户请求一个ASP网页时,在返回的HTTP消息头中会有一行:
Set-Cookie: ASPSESSIONIDCSQCRTBS=KOIPGIMBCOCBFMOBENDCAKDP; path=/
服务器通过COOKIE的方式告诉客户端你的SESSIONID是多少,在这里是“KOIPGIMBCOCBFMOBENDCAKDP”,并且服务器上保留了和此SESSIONID相关的数据,当同一用户再次发送请求时,还会把这个COOKIE再发送回去,服务器端根据此ID找到此用户的数据,也就实现了服务器端用户状态的保存。所以我们用ASP编程时可以使用“session("name")=user”这样的方式保存用户信息。注意此COOKIE内容里并没有过期时间,这表示这是一个当关闭浏览器时立即过期的COOKIE,它不会被保存到硬盘上。这种工作方式比单纯用COOKIE的方式要安全很多,因为在客户端并没有什么能让我们修改和欺骗的值,唯一的信息就是SESSIONID,而这个ID在浏览器关闭时会立即失效,除非别人能在你浏览网站期间或关闭浏览器后很短时间内知道此ID的值,才能做一些欺骗活动。因为服务器端判断SESSION过期的方式并不是断开连接或关闭浏览器,而是通过用户手工结束SESSION或等待超时,当用户关闭浏览器后的一段时间里SESSION还没有超时,所以这时如果知道了刚才的SESSIONID,还是可以欺骗的。因此最安全的办法还是在离开网站之前手工结束SESSION,很多网站都提供“Logout”功能,它会通过设置SESSION中的值为已退出状态或让SESSION立即过期从而起到安全的目的。
SESSION和COOKIE的方式各有优缺点。SESSION的优点是比较安全,不容易被欺骗,缺点是过期时间短,如果用过在超过过期时间里没有向服务器发送任何信息,就会被认为超过过期了;COOKIE则相反,根据服务器端设置的超时时间,可以长时间保留信息,即使关机再开机也可能保留状态,而安全性自然大打折扣。很多网站都提供两种验证方式相结合,如果用户临时用这台电脑访问此访问则需要输入用户名和密码,不保存COOKIE;如果用户使用的是自己的个人电脑,则可以让网站在自己硬盘上保留COOKIE,以后访问时就不需要重新输入用户名和密码了。
 
4 POST
浏览器访问服务器常用的方式有GET和POST两种,GET方式只发送HTTP消息头,没有消息体,也就是除了要GET的基本信息之外不向服务器提供其他信息,网页表单(FROM)的默认提交方式就是用GET方式,它会把所有向服务器提交的信息都作为URL后面的参数,如a.asp?a=1&b=2这样的方式。而当要提交的数据量很大,或者所提交内容不希望别人直接看到时,应该使用POST方式。POST方式提交的数据是作为HTTP消息体存在的,例如,写一个网页表单:
<form method=post>
<input type=text name=text1>
<input type=submit>
</form>
访问此网页,并在表单中填入一个“haha”,然后提交,可以看到此次提交所发送的信息如下:
POST /form.asp HTTP/1.1
Accept: **
Referer: http://localhost:8080/form.asp
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d62bf2f9066c
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Host: localhost:8080
Content-Length: 337
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: key=haha; ASPSESSIONIDCSQCRTBS=LOIPGIMBLMNOGCOBOMPJBOKP
-----------------------------7d62bf2f9066c
Content-Disposition: form-data; name="text1"
hehe
-----------------------------7d62bf2f9066c
Content-Disposition: form-data; name="file1"; filename="H:/Documents and Settings/Administrator/桌面/haha.txt"
Content-Type: text/plain
ABCDEFG
-----------------------------7d62bf2f9066c--
 
显然这个提交的信息要比前述的复杂很多。Content-Type变成了“multipart/form-data”,后面还多了一个boundary,此值是为了区分POST的内容的区段用的,只要在内容中遇到了此值,就表示下面要开始一个新的区段了,每个区段的内容相对独立。如果遇到的是此值后面连着两个减号,则表示全部内容到此结束。每个段也分为段头和段体两部分,用空行隔开,每段都有自己的类型和相关信息。如第一区段是text1的值,它的名称是“text1”,值为“hehe”。第二段是文件内容,段首里表明了此文件域的名称“file1”和此文件在用户磁盘上的位置,后面就是文件的内容。
如果我们想要自己写一个上传文件组件来接收HTML表单传送的文件数据,那么最核心的任务就是解析此数据包,从中取得需要的信息。
 
 
 

理解HTTP消息头 (四)
服务器返回的消息

服务器返回的HTTP消息也分为消息头和消息体两部分。前面连载的第二篇里已经介绍了返回消息中常见返回代码的含义。对于非正常的返回代码的处理比较简单,只要照着要求去做就好了,而对于正常的返回代码(200),其处理方式就多种多样了。

1 Content-Type

Content-Type是返回消息中非常重要的内容,它标识出这个返回内容的类型,其值为“主类型/子类型”的格式,例如最常见的就是text/html,它的意思是说返回的内容是文本类型,这个文本又是HTML格式的。原则上浏览器会根据Content-Type来决定如何显示返回的消息体内容。常见的内容类型有:
text/html HTML文本
image/jpeg JPG图片
image/gif GIF图片
application/xml XML文档
audio/x-mpegurl MP3文件列表,如果安装了Winamp,则可以直接把它当面M3U文件来打开
更多的内容类型可以在注册表“HKCR/MIME/Database/Content Type”下看到
对于IE6浏览器来说,如果Content-Type中的类型和实际的消息体类型不一致,那么它会根据内容中的类型来分析实际应该是什么类型,对于JPG、GIF等常用图片格式都可以正确的识别出来,而不管Content-Type中写的是什么。
如果Content-Type中指定的是浏览器可以直接打开的类型,那么浏览器就会直接打开其内容显示出来,如果是被关联到其它应用程序的类型,这时就要查找注册表中关于这种类型的注册情况,如果是允许直接打开而不需要询问的,就会直接调出这个关联的应用程序来打开这个文件,但如果是不允许直接打开的,就会询问是否打开。对于没有关联到任何应用程序的类型,IE浏览器不知道它该如何打开,此时IE6就会把它当成XML来尝试打开。

2 Content-Disposition

如果用AddHeader的方法在HTTP消息头中加入Content-Disposition段,并指定其值为“attachment”,那么无论这个文件是何类型,浏览器都会提示我们下载此文件,因为此时它认为后面的消息体是一个“附件”,不需要由浏览器来处理了。例如,在ASP.Net中写入如下语句:
Response.AddHeader("Content-Disposition: attachment");
请求此页面是得到的结果如:
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Thu, 23 Mar 2006 07:54:53 GMT
Content-Disposition: attachment
Cache-Control: private
Content-Type: text/html; charset=utf-8
……
也就是说,通过AddHeader函数可以为HTTP消息头加入我们自定义的内容。使用这种方法可以强制让浏览器提示下载文件,即使这个文件是我们已知的类型,基于是HTML网页。如果想要让用户下载时提示一个默认的文件名,只需要在前面一句话后加上“filename=文件名”即可。例如:
Response.AddHeader("Content-Disposition: attachment; filename=mypage.htm");

3 Content-Type与Content-Disposition

如果把Content-Type和Content-Disposition结合在一起使用会怎么样呢?
打开一个网页时,浏览器会首先看是否有Content-Disposition: attachment这一项,如果有,无论Content-Type的值是什么,都会提示文件下载。
如果指定了filename,就会提示默认的文件名为此文件名。注意到在IE6中除了“保存”按扭外还有“打开”按扭,此时打开文件的类型是由在filename中指定的文件扩展名决定的,例如让filename=mypic.jpg,浏览器就会查找默认的图片查看器来打开此文件。
如果没有指定filename,那么浏览器就根据Content-Type中的类型来决定文件的类型,例如Content-Type类型为image/gif,那么就会去查找默认的看GIF图片的工具,并且设置此文件的名字为所请求的网页的主名(不带扩展名)加上对应于此文件类弄扩展名,例如请求的mypage.aspx,就会自动变成mypage.gif。如果并没有指定Content-Type值,那么就默认它为“text/html”,并且保存的文件名就是所请求的网页文件名。
但如果没有指定Content-Disposition,那么就和前面关于Content-Type中所讨论的情况是一样的了。

4 Cache

返回消息中的Cache用于指定网页缓存。我们经常可以看到这样的情况,打开一个网页时速度不快,但再次打开时就会快很多,原因是浏览器已经对此页面进行了缓存,那么在同一浏览器窗口中再次打开此页时不会重新从服务器端获取。网页的缓存是由HTTP消息头中的“Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。其作用根据不同的重新浏览方式分为以下几种情况:
(1) 打开新窗口
如果指定cache-control的值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:
Cache-control: max-age=5
表示当访问此网页后的5秒内再次访问不会去服务器
(2) 在地址栏回车
如果值为private或must-revalidate(和网上说的不一样),则只有第一次访问时会访问服务器,以后就不再访问。如果值为no-cache,那么每次都会访问。如果值为max-age,则在过期之前不会重复访问。
(3) 按后退按扭
如果值为private、must-revalidate、max-age,则不会重访问,而如果为no-cache,则每次都重复访问
(4) 按刷新按扭
无论为何值,都会重复访问

当指定Cache-control值为“no-cache”时,访问此页面不会在Internet临时文章夹留下页面备份。
另外,通过指定“Expires”值也会影响到缓存。例如,指定Expires值为一个早已过去的时间,那么访问此网时若重复在地址栏按回车,那么每次都会重复访问:
Expires: Fri, 31 Dec 1999 16:00:00 GMT

在ASP中,可以通过Response对象的Expires、ExpiresAbsolute属性控制Expires值;通过Response对象的CacheControl属性控制Cache-control的值,例如:
Response.ExpiresAbsolute = #2000-1-1# ' 指定绝对的过期时间,这个时间用的是服务器当地时间,会被自动转换为GMT时间
Response.Expires = 20  ' 指定相对的过期时间,以分钟为单位,表示从当前时间起过多少分钟过期。
Response.CacheControl = "no-cache"
Expires值是可以通过在Internet临时文件夹中查看临时文件的属性看到的,如:


TAv_d7hXV61CXJUUz0Ix75MDZSszcxddhXU2eMySWmZcLKEyZQMI5" WIDTH="199">
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息