Back

Http笔记

浏览器输入URL到返回页面的过程

  1. 根据域名,进行DNS域名解析
  2. 拿到解析的IP地址,建立TCP连接
  3. 向IP地址发送HTTP请求
  4. 服务器处理请求
  5. 返回响应结果
  6. 关闭TCP连接
  7. 浏览器解析HTML
  8. 浏览器布局渲染

简介

HTTP即超文本传输协议(HTTP,Hyper Text Transport Protocol)。HTTP协议默认监听80端口,主要用于描述请求和响应的数据格式。

版本

  • 0.9 已过时。只接受GET一种请求方法,没有在通讯中指定版本号,且不支持请求头。
  • HTTP/1.0 建立连接后只能请求响应一次
  • HTTP/1.1 持久连接(可以进行多次请求和响应)被默认采用,能很好地配合代理服务器工作。还支持以管道方式同时发送多个请求,以便降低线路负载,提高传输速度
    • 维持和服务器已经建立的 TCP 连接,在同一连接上顺序处理多个请求
    • 刷新页面不需要重新建立 SSL 连接
    • 和服务器建立多个 TCP 连接
    • Pipelining 实现同一时刻只能处理一个请求
      • 浏览器是没有办法根据响应结果来判断响应对应于哪一个请求的
      • 一些代理服务器不能正确的处理 HTTP Pipelining
      • Head-of-line Blocking 连接头阻塞
  • HTTP/2 多个 HTTP 请求可以在同一个 TCP 连接中并行进行(Multiplexing )

浏览器对同一 Host 建立 TCP 连接到数量有没有限制

有。Chrome 最多允许对同一个 Host 建立六个 TCP 连接。不同的浏览器有一些区别。

消息头

请求的资源中含有 <img > <link> <script>浏览器会自动发出请求

请求消息头:一个请求行,多个消息头, 一个空行
请求行:请求类型(GET/POST) 请求资源 HTTP版本 如(GET /app/2.html HTTP/1.1)

响应消息头:一个响应头(状态行),多个消息头,一个空行,响应内容

GET与POST方式对比

  1. GET提交数据有长度限制,1K,而POST没有长度限制
  2. GET皎在地址栏可见,所以不安全。POST提交数据在主体内容中不可见,所以安全

请求消息头

Accept:告知服务器,浏览器可接受的MIME类型 (Multipurpose Internet Mail Extensation) 多用途互联网邮件扩展类型
	MIME 类型:文件系统文件类型用文件的扩展名来区分
	MIME类型由大类型/小类型组成的.比如text/html text/css text/javascript image/bmp image/jpeg (Tomcat conf/web.xml
Accpept-Charset:支持的字符集
Accept-Language:浏览器所希望的语言类型
Accpet-Encoding:gzip,deflate
*Referer:包含一个URL,该URL表示当前页来源(用于防盗链,统计广告投放效果)
Content-Type:请求正文内容的MIME类型(适应于Post请求)
	默认是application/x-www-form-urlencoded(username=sa&age=30)
	还有:application/json、multipart/form-data

响应消息头

*Location:http://www.itheima.com/index.jsp 告知浏览器,新的资源的位置(302跳转)
*Content-Encoding: gzip代表服务器采用什么方式进行数据压缩
*Content-Length:  服务器发送的数据长度
Content-Language: zh-cn服务发送的文本的语言
*Content-Type: text/html; charset=GB2312服务器发送的内容的MIME类型
Last-Modified:服务器最后修改资源的时间
*Refresh:指定服务器刷新  Refresh: 1;url=http://www.it315.org指示客户端刷新频率。单位是秒
*Content-Disposition: attachment; filename=aaa.zip指示客户端下载文件

*Expires: -1清理缓存
*Cache-Control: no-cache (1.1)  没有缓存
*Pragma: no-cache   (1.0) 没有缓存

*Set-Cookie:SS=Q0=5Lb_nQ; path=/search服务器端发送的Cookie

HTTPS

HTTP:互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

HTTPS:以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

区别:

  1. https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用;
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议;
  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443;
  4. http的连接很简单,是无状态的;HTTPS是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

如果不用HTTPS,HTTP协议如何安全的传输密码信息?

HTTP协议是纯文本协议,没有任何加密措施。通过HTTP协议传输的数据都可以在网络上被完全监听。如果用户登陆时将用户名和密码直接明文通过HTTP协议传输过去了,那么密码可能会被黑客窃取。

一种方法是使用非对称加密。GET登陆页面时,将公钥以Javascript变量的形式暴露给浏览器。然后用公钥对用户的密码加密后,再将密码密文、用户名和公钥一起发送给服务器。

服务器会提前存储公钥和私钥的映射信息,通过客户端发过来的公钥就可以查出对应的私钥,然后对密码密文进行解密就可以还原出密码的明文。

为了加强公钥私钥的安全性,服务器应该动态生成公钥私钥对,并且使用后立即销毁。但是动态生成又是非常耗费计算资源的,所以一般服务器会选择Pool方法提供有限数量的公钥私钥对池,然后每隔一段时间刷新一次Pool。

文件路径攻击

很多操作系统都会使用..符号表示上层目录。如果黑客在URL的路径里面使用..符号引用上层目录,而服务器没有做好防范的话就有可能导致黑客可以直接访问权限之外的文件。比如使用多级..符号就可以引用到根目录,进一步就可以访问任意文件。 所以很多服务器都禁止在URL路径里出现..符号以避免被攻击。

文件路径攻击也是很多黑客非常喜爱使用的攻击方法之一。如果你的服务器有一定的访问量,打开你的nginx日志,你就会偶尔发现有一些奇怪的URL里面有一堆..符号,这种URL的出现就表示网络上的黑客正在尝试攻击你的服务器。

DNS欺骗

HTTP协议严重依赖于DNS域名解析。任意一个域名类网址的访问都需要经过域名解析的过程得到目标服务的IP地址才能成功继续下去。

如果掌管DNS服务的运营商作恶将域名解析到不正确的IP,指向一个钓鱼的网页服务。用户如果没有觉察,就可能会将自己的敏感信息提交给冒牌的服务器。

谨慎使用外部的HTTP代理(中间人攻击)

HTTP代理作为客户端到服务器之间的中间路由节点,它起到传话人和翻译官的角色。 如果这个翻译官不靠谱的话,客户端是会拿到错误的返回数据的。它同DNS欺骗一样,是可以对客户端进行钓鱼攻击的。

如果这个翻译官口风不严的话,它可能会将它听到的敏感信息泄露给别人。

CSRF(Cross-Site Request Forgery)

CSRF跨站请求伪造有很多别名,比如One-Click Attack(一键攻击),比如Session Riding(搭便车攻击)

假设在在一个社区博客网站中,删除个人的文章只需要一个URL就可以,Cookie中的会话权限信息会自动附加到请求上。

# 123456为文章的ID
http://example.com/blog/123456/delete

那么当别人伪造了一个上面的链接地址诱惑你去点击,比如通过站内信件、私聊、博客评论、图片链接或者在别的什么网站上随机制造的一个链接。

你不经意点了一下,就丢了你的文章。所以它被称为一键攻击。因为这是借用了你当前登陆的会话信息来搞事,所以也被称为搭便车攻击。

如果在一个金融系统中,转账要是也可以通过一个简单的URL进行的话,那这种危险就非同小可。

这就要求修改性的操作务必不得使用简单的GET请求进行处理。但是即使这种情况下你改成了POST请求,黑客依然有办法伪造请求,那就是通过iframe。

黑客在别的什么网站上伪造了一个POST表单,诱惑你去submit。如果只是普通的内嵌进HTML网页的表单,用户提交时会出现跨域问题。因为当前网站的域名和表单提交的目标域名不一致。但是如果通过iframe来内嵌表单,则可以绕过跨域的问题,而用户却完全没有任何觉察。

为了防范CSRF攻击,聪明的网站的POST表单里都会带上CSRF_TOKEN这个隐藏字段。CSRF_TOKEN是根据用户的会话信息生成的。当表单提交时,会将token和用户的会话信息做比对。如果匹配就是有效的提交请求。

<form method="POST" action="/blog/delete">
<label for="blog_id">博客ID</label>
<input type="text" name="blog_id" value="12345">
<input type="hidden" name="csrf_token" value="xxxxxxxxxxxx">
</form>

黑客必须拿到CSRF_TOKEN才可以借用用户的会话信息实施CSRF攻击,但是CSRF_TOKEN又必须由用户的会话信息才可以生成。黑客没有用户的会话信息,从而无法实施CSRF攻击。

XSS(Cross Site Scripting)

如果黑客可以在你的网页中植入任意Javascript脚本,那他就可以随意鱼肉你的账户。通过Javascript可以获取Cookie的信息,可以借用你的会话去调用一些隐秘的API,而这一些行为都是在偷偷的进行,你根本完全不知道。

<div>
# 用户内容Start
<script>send_to_hacker(document.cookie)</script>
# 用户内容END

</div>

这类攻击在一些UGC网站中非常常见,常见的博客类网站就是UGC网站,用户可以通过编辑内容来生成网页。

黑客也是用户。他可以编辑一段Javascript脚本作为内容提交上去。如果服务器没有做好防范,这段脚本就会在生成的网页中运行起来。当其它用户在登陆的状态下来浏览这个网页的时候,就悲剧了。

防范XSS一般是通过对输出的内容进行内容替换做到的。在HTML页面中不同的位置会有不同的内容替换规则。 比较常见的是使用HTML entity编码将HTML标签之间的内容中的一些特殊的字符进行转码。

<div>
# safe now
&lt;script&gt;send_to_hacker(document.cookie)&lt;/script&gt;
</div>

还有些UGC内容在HTML标签的属性中、Javascript的变量中、URL、css代码中,他们转码的规则并不一样,具体方法可以去Google相关文档。

跨域

跨域是个很头痛的问题。

当你有多个后端服务,但是只有一个前端的时候,你想做前后端分离,就会遇到跨域问题。你发现你的前端js调用后端服务时控制台告诉你不ok。然后只好把这些服务都挂在了同一个nginx域名下面,通过url前缀区分。

这时候你会想,跨域太TM讨厌了。既然跨域这么讨厌,那为什么浏览器非要限制跨域呢?

还是安全原因。

让我们回到上文的搭便车攻击(Session Riding),也就是骑着别人的会话来搞事情。

假设现在你的浏览器开了一个站点A,登陆了进去,于是cookie便记录了会话id。 然后你又不小心开了另一个站点B,这个站点页面一打开就开始执行一些恶意代码。这些代码的逻辑是调用站点A的API来获取站点A的数据,因为可以骑着(Ride)站点A的会话cookie。而这些数据正好是用户私密性的。于是用户在站点A上的私有信息就被站点B上的代码窃走了。这就是跨域的风险。

但是有时候我们又希望共享数据给不同的站点,该怎么办呢?

答案是JSONP & CORS

JSONP(JSON Padding)

JSONP通过HTML的script标记实现了跨域共享数据的方式。JSON通过在网页里定义一个回调方法,然后在页面上插入一个动态script标签,指向目标调用地址。服务器会返回一段javascript代码,一般是some_callback(data)这种形式的回调。该段代码会在浏览器里自动执行,于是网页就得到了跨域服务器返回的数据。

<script>
function some_callback(data) {
   console.log(data)
}
</script>
<script src="http://example.com/someapi?callback=some_callback">
</script>

因为JSONP是不携带cookie信息的,所以能有效避免搭便车攻击。JSONP是否可以获取到数据还需要服务器对这种调用提供显示支持,服务器必须将数据以javascript代码的形式返回才可以传递给浏览器。

CORS(Cross-Origin Resource Sharing)

JSONP的不足在于它只能发送GET请求,并且不能携带cookie。而CORS则可以发送任意类型的请求,可以选择性携带cookie。

CORS是通过Ajax发送的跨域请求技术。CORS的请求分为两种,一种是简单请求,一种是复杂请求。简单请求就是头部很少很简单的GET/HEAD/POST请求。复杂请求就是非简单请求。

浏览器发现Ajax的请求是跨域的,就会在请求头添加一个Origin参数,指明当前请求的发起站点来源。服务器根据Origin参数来决定是否授权。

如果是简单请求,Ajax直接请求服务器。服务器会当成普通的请求直接返回内容,不同的是还会在响应头部添加几个重要的头部,其中最重要的头部是Access-Control-Allow-Origin: http://example.com

浏览器如果在响应中没有读到这个头部,就会通知Ajax请求失败。虽然服务器返回了数据,浏览器也不让脚本读到数据,这就保证了跨域的安全。服务器就是通过请求的Origin参数来决定要不要响应Access-Control-Allow-Origin头部来决定是否允许指定网站的跨域请求。

如果是复杂请求,要走一个预检的流程。预检就是浏览器先向服务器发送一个Method为Options的请求,如果服务器允许跨域请求,浏览器再发起这个Ajax请求。所以CORS的复杂请求会比简单请求额外耗费一个TTL的时间。

REF

HTTP协议又冷又实用的技能大全!

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus