Hero Image
HTTP笔记

#http-code http协议(超文本传输协议) 是客户端和服务器端两者通信共同遵循的一些规则。主要内容是定义了客户端如何向服务器请求资源,服务器如何响应客户端请求。 请求中的POST与GET方法的区别 get是从服务器上获取数据,post是向服务器传送数据。 在客户端,Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在HTML HEADER内提交。 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。 GET方式提交的数据最多只能有1024字节,而POST则没有此限制。 安全性问题。正如在(1)中提到,使用 GET 的时候,参数会显示在地址栏上,而 Post 不会。所以,如果这些数据是中文数据而且是非敏感数据,那么使用 GET;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。 HTTP 1.0 HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接 当一个网页文件中包含了很多图像的地址的时候,那就需要很多次的HTTP请求和响应,每次请求和响应都需要一个单独的连接,每次连接只是传输一个文档和图像,上一次和下一次请求完全分离。即使图像文件都很小,但是客户端和服务器端每次建立和关闭连接却是一个相对比较费时的过程,并且会严重影响客户机和服务器的性能。当一个网页文件中包含JS文件,CSS文件等内容时,也会出现类似上述的情况。 HTTP 1.1 为了克服HTTP 1.0的这个缺陷,HTTP 1.1支持持久连接(HTTP/1.1的默认模式使用带流水线的持久连接),在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。 HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。 在HTTP 1.1,request和response头中都有可能出现一个connection的头,此header的含义是当client和server通信时对于长链接如何进行处理。 在HTTP 1.1中,client和server都是默认对方支持长链接的, 如果client使用HTTP 1.1协议,但又不希望使用长链接,则需要在header中指明connection的值为close;如果server方也不想支持长链接,则在response中也需要明确说明connection的值为close。不论request还是response的header中包含了值为close的connection,都表明当前正在使用的tcp链接在当天请求处理完毕后会被断掉。以后client再进行新的请求时就必须创建新的tcp链接了。 HTTP 1.1在继承了HTTP 1.0优点的基础上,也克服了HTTP 1.0的性能问题。 HTTP 1.1通过增加更多的请求头和响应头来改进和扩充HTTP 1.0的功能。如,HTTP 1.0不支持Host请求头字段,浏览器无法使用主机头名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在HTTP 1.1中增加Host请求头字段后,WEB浏览器可以使用主机头名来明确表示要访问服务器上的哪个WEB站点,这才实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点。HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。HTTP 1.1还提供了与身份认证、状态管理和Cache缓存等机制相关的请求头和响应头。HTTP 1.0不支持文件断点续传,RANGE:bytes是HTTP 1.1新增内容,HTTP 1.0每次传送文件都是从文件头开始,即0字节处开始。RANGE:bytes=XXXX表示要求服务器从文件XXXX字节处开始传送,这就是我们平时所说的断点续传。 HTTP 1.1和HTTP 1.0协议的区别 缓存处理 带宽优化及网络连接的使用 错误通知的管理 消息在网络中的发送 互联网地址的维护 安全性及完整性 HTTP 1.x和HTTP 2协议的区别 二进制分帧:HTTP 2采用二进制格式传输数据,而非HTTP 1.x的文本格式 头部压缩:头部表在HTTP 2的连接存续期内始终存在,由客户端和服务器共同渐进地更新。请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销 多路复用:直白的说就是所有的请求都是通过一个TCP连接并发完成。HTTP 1.x虽然通过pipeline也能并发请求,但是多个请求之间的响应会被阻塞的,所以pipeline至今也没有被普及应用,而HTTP 2做到了真正的并发请求。同时,流还支持优先级和流量控制。 服务器推送:服务端能够更快的把资源推送给客户端。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML再发送这些请求。当客户端需要的时候,它已经在客户端了。 HTTP 2主要是HTTP 1.

Hero Image
OAuth 2.0扩展协议PKCE

#oauth PKCE全称是Proof Key for Code Exchange,在2015年发布,它是OAuth 2.0核心的一个扩展协议,所以可以和现有的授权模式结合使用,比如Authorization Code+PKCE, 这也是最佳实践,PKCE最初是为移动设备应用和本地应用创建的, 主要是为了减少公共客户端的授权码拦截攻击。 在最新的OAuth 2.1规范中,推荐所有客户端都使用PKCE,而不仅仅是公共客户端,并且移除了Implicit隐式和Password模式,那之前使用这两种模式的客户端怎么办? 是的,现在都可以尝试使用Authorization Code+PKCE的授权模式。那PKCE为什么有这种魔力呢? 实际上它的原理是客户端提供一个自创建的证明给授权服务器,授权服务器通过它来验证客户端,把访问令牌(access_token)颁发给真实的客户端而不是伪造的。 客户端类型 上面说到了PKCE主要是为了减少公共客户端的授权码拦截攻击,那就有必要介绍下两种客户端类型了。 OAuth 2.0核心规范定义了两种客户端类型, confidential 机密的, 和 public 公开的, 区分这两种类型的方法是, 判断这个客户端是否有能力维护自己的机密性凭据 client_secret。 confidential 对于一个普通的web站点来说,虽然用户可以访问到前端页面,但是数据都来自服务器的后端api服务,前端只是获取授权码code,通过code换取access_token这一步是在后端的api完成的,由于是内部的服务器,客户端有能力维护密码或者密钥信息,这种是机密的的客户端。 public 客户端本身没有能力保存密钥信息,比如桌面软件,手机App,单页面程序(SPA),因为这些应用是发布出去的,实际上也就没有安全可言,恶意攻击者可以通过反编译等手段查看到客户端的密钥,这种是公开的客户端。 在OAuth 2.0授权码模式(Authorization Code)中,客户端通过授权码code向授权服务器获取访问令牌(access_token)时,同时还需要在请求中携带客户端密钥(client_secret),授权服务器对其进行验证,保证access_token颁发给了合法的客户端,对于公开的客户端来说,本身就有密钥泄露的风险,所以就不能使用常规OAuth 2.0的授权码模式,于是就针对这种不能使用client_secret的场景,衍生出了Implicit隐式模式,这种模式从一开始就是不安全的。在经过一段时间之后,PKCE扩展协议推出,就是为了解决公开客户端的授权安全问题。 授权码拦截攻击 上面是OAuth 2.0授权码模式的完整流程,授权码拦截攻击就是图中的C步骤发生的,也就是授权服务器返回给客户端授权码的时候,这么多步骤中为什么C步骤是不安全的呢?在OAuth 2.0核心规范中,要求授权服务器的anthorize endpoint和token endpoint必须使用TLS(安全传输层协议)保护,但是授权服务器携带授权码code返回到客户端的回调地址时,有可能不受TLS的保护,恶意程序就可以在这个过程中拦截授权码code,拿到code之后,接下来就是通过code向授权服务器换取访问令牌access_token,对于机密的客户端来说,请求access_token时需要携带客户端的密钥client_secret,而密钥保存在后端服务器上,所以恶意程序通过拦截拿到授权码code也没有用,而对于公开的客户端(手机App,桌面应用)来说,本身没有能力保护client_secret,因为可以通过反编译等手段,拿到客户端client_secret,也就可以通过授权码code换取access_token,到这一步,恶意应用就可以拿着token请求资源服务器了。 state参数,在OAuth 2.0核心协议中,通过code换取token步骤中,推荐使用state参数,把请求和响应关联起来,可以防止跨站点请求伪造-CSRF攻击,但是state并不能防止上面的授权码拦截攻击,因为请求和响应并没有被伪造,而是响应的授权码被恶意程序拦截。 PKCE 协议流程 PKCE协议本身是对OAuth 2.0的扩展,它和之前的授权码流程大体上是一致的。区别在于,在向授权服务器的authorize endpoint请求时,需要额外的code_challenge和code_challenge_method参数,向token endpoint请求时,需要额外的code_verifier参数,最后授权服务器会对这三个参数进行对比验证,通过后颁发令牌。 原理分析 上面我们说了授权码拦截攻击,它是指在整个授权流程中,只需要拦截到从授权服务器回调给客户端的授权码code,就可以去授权服务器申请令牌了,因为客户端是公开的,就算有密钥client_secret也是形同虚设,恶意程序拿到访问令牌后,就可以光明正大的请求资源服务器了。 PKCE是怎么做的呢?既然固定的client_secret是不安全的,那就每次请求生成一个随机的密钥(code_verifier),第一次请求到授权服务器的authorize endpoint时,携带code_challenge和code_challenge_method,也就是code_verifier转换后的值和转换方法,然后授权服务器需要把这两个参数缓存起来,第二次请求到token endpoint时,携带生成的随机密钥的原始值(code_verifier),然后授权服务器使用下面的方法进行验证: plain code_challenge = code_verifier sha256 code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) 通过后才颁发令牌,那向授权服务器authorize endpoint和token endpoint发起的这两次请求,该如何关联起来呢?通过授权码code即可,所以就算恶意程序拦截到了授权码code,但是没有code_verifier,也是不能获取访问令牌的,当然PKCE也可以用在机密(confidential)的客户端,那就是client_secret+code_verifier双重密钥了。 参考连接 oauth文档