http首部字段
以下内容大都转载和参考自《图解HTTP》
通用首部字段:
1、Cache-Control, 控制缓存的行为,多个指令之间通过“,”分隔,如Cache-Control: private, max-age=0, no-cache。缓存是指代理服务器(缓存服务器是代理服务器的一种)或客户端本地磁盘内保存的资源副本,即使存在缓存,也会因为客户端的要求或缓存的有效期等因素向源服务器确认资源的有效性。
缓存请求指令:
no-cache,防止接收过期的资源,指示代理服务器(缓存服务器)每次都向源服务器确认资源的有效期。
no-store, 不缓存该请求的任一部分,暗示请求中包含机密信息。
max-age=[秒], 参数值必须,如果缓存服务器上的缓存资源的时长比该值小则接收缓存的资源,该值如果为0的话通常缓存服务器会将请求转发给源服务器。http/1.1版本的服务器会优先处理max-age而忽略掉Expires,http/1.0版本服务器则相反。

max-stale(=[秒]),即使缓存资源已过期,只要在指定时间内则接收响应资源,不指定参数值的话表示不论过了多久都接收响应。
min-fresh=[秒],参数值必须,指定服务器返回还未过指定时间的缓存资源。
no-transform,缓存不能改变主体的媒体类型,防止代理压缩图片等操作。
only-if-cached, 只请求缓存服务器上的缓存资源,不对缓存资源有效期确认,如果缓存服务器的本地缓存无响应则返回状态码504 Gateway Timeout。
缓存响应指令:
public, 可以使用缓存。
private, 指示代理服务器(缓存服务器)只对特定用户提供资源缓存服务。
no-cache(=[value]), 参数值可选,当指定参数值后指示缓存服务器不再对资源进行缓存,如Cache-Control: no-cache=Location。
no-store, 不缓存该响应的任一部分,暗示响应中包含机密信息。
no-transform, 缓存不能改变主体的媒体类型,防止代理压缩图片等操作。
must-revalidate, 指示代理服务器在返回响应的缓存资源前向源服务器验证该缓存目前是否有效,如果代理无法连接源服务器的话会返回504 Gateway Timeout状态码,使用该指令会
忽略请求的max-stale指令。
proxy-revalidate,指示代理服务器对缓存资源的有效性进行确认。
max-age=[秒], 参数值必须,指示缓存的有效时间,缓存服务器在该时间内不必再向源服务器确认缓存资源的有效性。
s-maxage=[秒], 参数值必须,与max-age功能相同,不同的是该指令只适用于供多位用户使用的公共缓存服务器,使用该指令后会忽略对Expires首部字段及max-age指令的处理。
另外,可以使用自定义的指令,但这种扩展的指令仅对能理解它的代理服务器有意义。如下的community指令,Cache-Control本身没有这个指令,如果缓存服务器不能理解这个指令,则会忽略它:
Cache-Control: private, community="UCI"
2、Connection,管理持久连接和控制不再转发的首部字段。如当服务器想明确断开连接的时候发送首部Connection: close。
在http/1.1之前版本协议上使用持久连接的话客户端需要发送Connection: Keep-Alive(服务端会返回Connection:keep-alive的响应以指示客户端可以重用连接)。而在HTTP1.1中默认就是长连接(指定的时间内没有数据传输的话才关闭连接),如果客户端不希望使用长链接的话需要指定首部Connection: close。使用长连接的好处如下图所示:

可以设置Keep-Alive模式的属性,通过Keep-Alive首部,如下所示表示这个TCP通道可以保持5秒,而且这个长连接最多接收100次请求就断开:
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
下面是使用QQ浏览器向Tomcat服务发送一个普通请求和应答的HTTP包的首部和头,可以看到Tomcat返回的应答中Keep-Alive超时值为20秒,超过该值没有数据传输的话Tomcat服务会自动关闭该连接,Tomcat中配置该超时值的话在server.xml 中的Connector元素的keepAliveTimeout:


Connection: Upgrade则是指示不再转发Upgrade首部。
3、Date,表明创建http报文的日期时间,如Date: Tue, 03 Jul 2012 04:40:59 GMT,还有另外一种格式与C中asctime()输出格式一致。
4、Pragma,http/1.1之前版本的遗留字段,只用在客户端发送的请求中,要求所有的中间服务器不返回缓存的资源:Pragma: no-cache。如果所有的中间服务器都使用http/1.1版本的话则应直接使用Cache-Control: no-cache。
5、Trailer,指示在报文主体之后记录了那些首部字段,Trailer用在http/1.1响应首部中允许发送方在分块发送的消息后面添加额外的元信息,如:


6、Transfer-Encoding,设置传输报文主体时的编码方式为分块编码传输:Transfer-Encoding: chunked。
通常情况下,HTTP的响应消息体 message body 是作为整包发送到客户端的,用头『Content-Length』 来表示消息体的长度, 这个长度对客户端非常重要,因为对于持久连接TCP并不会在请求完立马结束,而是可以发送多次请求/响应,客户端需要知道哪个位置才是响应消息的结束,以及后续响应的开始,因此Content-Length显得尤为重要,服务端必须精确地告诉客户端 message body 的长度是多少, 如果Content-Length 比实际返回的长度短,那么就会造成内容截断,如果比实体内容长,客户端就一直处于pendding状态,直到所有的 message body 都返回了请求才结束。
分块编码传输是另一种解决方案:它把数据分解成一系列数据块,并以多个块发送给客户端,服务器发送数据时不再需要预先告诉客户端发送内容的总大小,只需在响应头里面添加Transfer-Encoding: chunked,以此来告诉浏览器我使用的是分块传输编码,这样就不需要 Content-Length 了,这就是分块传输编码 Transfer-Encoding 的作用。分块编码必须以0长度的块结束,如下指定了使用分块传输编码,且被分成3312字节和914字节大小的两块数据:

HTTP 1.1引入分块传输编码提供了以下几点好处:
①、HTTP分块传输编码允许服务器为动态生成的内容维持HTTP持久连接。通常,持久链接需要服务器在开始发送消息体前发送Content-Length消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。[动态内容,content-length无法预知]
②、分块传输编码允许服务器在最后发送消息头字段。对于那些头字段值在内容被生成之前无法知道的情形非常重要,例如消息的内容要使用散列进行签名,散列的结果通过HTTP消息头字段进行传输。没有分块传输编码时,服务器必须缓冲内容直到完成后计算头字段的值并在发送内容前发送这些头字段的值。[散列签名,需缓冲完成才能计算]
③、HTTP服务器有时使用压缩 (gzip或deflate)以缩短传输花费的时间。分块传输编码可以用来分隔压缩对象的多个部分。在这种情况下,块不是分别压缩的,而是整个负载进行压缩,压缩的输出使用本文描述的方案进行分块传输。在压缩的情形中,分块编码有利于一边进行压缩一边发送数据,而不是先完成压缩过程以得知压缩后数据的大小。[gzip压缩,压缩与传输同时进行]
比如下面为使用浏览器(70.21)向服务器(70.5:8080)请求一个页面的抓包,一开始浏览器创建了两个连接(一个端口为2388,一个为2389),这应该是浏览器为了提高效率所以提前多创建一个连接,这个跟浏览器特性有关,其它浏览器可能只会建立一个连接。可以看到,564-569为三次握手,790-934为四次挥手,570-573是浏览器请求网页数据和服务的应答,574-577为浏览器请求图标和服务的应答。

在571行有"tcp segment of a reassembled pdu"信息,表示HTTP分块传输,点击该行如下可以看到里面有头Transfer-Encoding: chunked,实体之前有首块的长度,可以看到这个长度文本显示为"18",是十六进制,转换成十进制的话是24,与要发送的实体数据大小相同:

点击572行可以看到分块的提示以及0长度的结尾块:

上面的测试Web服务使用的是Tomcat,所以Tomcat默认会使用分块编码?
7、Upgrade,检测能否使用更高版本的协议进行通信,因为Upgrade仅限于客户端和连接服务器之间,所以还需要额外指定Connection: Upgrade:

可以使用Upgrade来建立WebSocket通信方式。传统的HTTP协议是一种请求-响应模型,如果浏览器不发送请求,那么服务器无法主动给浏览器推送数据。如果要服务器主动向客户端推送信息,可以使用WebSocket。
客户端发送请求时,附带如下的几个头,就表示客户端希望升级连接,变成长连接的WebSocket:

服务器返回如下的响应表示升级成功,客户端收到成功响应后表示WebSocket“握手”成功,服务器可随时向浏览器推送消息,浏览器也可随时向服务器推送消息:

WebSocket协议也是建立在 TCP 协议之上,而且其握手阶段采用 HTTP 协议,所以默认端口也是80、443。WebSocket数据帧比Http更 轻量,协议标识符是ws(如果加密,则为wss)。
WebSocket建立连接通过http协议实现,因此,连接的发送方仍是客户端,确立WebSocket通信连接后服务端可以不必等待请求而直接向客户端推送数据,而且WebSocket是一直保持连接状态,首部信息量比Http要小。为了实现WebSocket通信,需要在HTTP连接建立后完成一次“握手”步骤:如下所示客户端通过使用HTTP的Upgrade首部字段,Upgrade用来告诉服务器通信协议发生改变,Sec-WebSocket-Key字段内记录着握手过程中必不可少的值,base64 编码的密文,要求服务端必须返回一个对应加密的“Sec-WebSocket-Accept”应答,Sec-WebSocket-Protocol字段内记录使用的子协议。

对于客户端的握手请求,服务器返回状态码101 Switching Protocols的响应,如下所示,Sec-WebSocket-Accept字段值是由客户端握手请求中的Sec-WebSocket-Key的字段值生成的(采用与客户端一致的密钥计算)。

成功握手确立WebSocket连接之后,通信不再使用Http的数据帧,而采用WebSocket的数据帧。

JavaScript可以调用"The WebSocket API"(W3C标准制定)内提供的WebSocket程序接口,以实现WebSocket下的全双工通信。websocket服务端则推荐使用node,开发效率和性能都很高,其它如go、python、springboot也可以实现websocket服务。 关于websocket客户端和服务端的实现,可以参考:阮一峰的网络日志——WebSocket教程。
var ws = new WebSocket(“ws://echo.websocket.org:12010”); //Websocket 依然使用 80 端口,运行在 TLS 上则使用 443 端口,也可以指定新的端口 ws.onopen = function(){ws.send(“Test!”); }; //客户端连接成功触发 onopen 消息 ws.onmessage = function(evt){console.log(evt.data);ws.close();}; //收到服务端数据触发onmessage消息 ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; //关闭连接触发onclose消息 ws.onerror = function(evt){console.log(“WebSocketError!”);}; //连接/发送/接收失败触发onerror消息
8、报文在经过代理或网关时,会在首部字段Via中附加该服务器的信息(使用的http版本等),Via首部是为了追踪传输路径,其经常和TRACE方法一起使用,比如代理服务器收到由TRACE方法发送过来的请求,当Max-Forwards: 0时代理服务器不再转发该请求,这时代理服务器将自身信息写入Via首部后返回该请求的响应。

9、Warning,该首部通常告知用户一些与代理缓存相关的问题的警告,Warning首部的格式及警告码内容如下:


请求首部字段:
1、Accept,通知服务器 用户代理(浏览器)能处理的媒体类型及其优先级,如text/*,image/*,*/*表示所有,媒体类型之间使用逗号分隔。常见的媒体类型如下所示,其中q用来指示优先级,q的值从0.0到1.0,默认为1.0:


2、Accept-Charset, 通知服务器 用户代理(浏览器)支持的字符集及字符集的优先级,如Accept-Charset: iso-8859-5, unicode-1-1;q=0.8。
3、Accept-Encoding,通知服务器 用户代理(浏览器)支持的内容编码(压缩类型)及编码的优先级,常见的内容编码有gzip、compress、deflate、identity(不执行压缩的默认编码格式),如Accept-Encoding: gzip, deflate,另外除了可以使用q来指定优先级外也可以使用通配符*来指定任意的编码格式。
4、Accept-Language, 通知服务器用户代理(浏览器)支持的自然语言集及其优先级,如Accept-Language: zh - CN, zh; q = 0.8, en; q = 0.2 表示优先选择简体中文,其次选择中文,最后选择英文,q表示权重。
5、Authorization, 告知服务器用户代理的认证信息(证书值),如下所示,关于Authorization认证的具体可以参考https://www.cnblogs.com/milanleon/p/9868684.html 中用户身份认证部分:

6、Expect, 客户端发送Expect:100-Continue握手的目的,是为了在客户端在发送请求内容之前,判断源服务器是否愿意接受请求(基于请求头部)。 xpect:100-Continue握手需谨慎使用,因为遇到不支持HTTP/1.1协议的服务器或者代理时会引起问题。
7、From,告知服务器使用用户代理的用户的电子邮箱地址。
8、Host, 告知服务器请求的资源所处的互联网主机名和端口,如Hots: www.hackr.jp:80,端口号省略的话http则使用默认端口80,https使用默认端口443。Host首部字段是HTTP/1.1中唯一一个必须包含在请求内的首部字段,如果服务器未设定主机名则Host值为空即可。
如下图表示使用GET方法请求域名为www.hackr.jp的根目录里的index.html文件,服务器收到后返回index.html文件。

首部字段Host和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联,这是首部字段Host必须存在的意义。请求被发送至服务器时,请求中的主机名会用IP地址直接替换解决。但如果这时,相同的IP地址下部署运行着多个域名,那么服务器就会被无法理解究竟是哪个域名对应的请求。因此,就需要使用首部字段Host来明确指出请求的主机名。
9、If-Match, 只有当If-Match的字段值跟请求资源的ETag值匹配时服务器才接受请求(这时的服务器无法使用弱ETag值),否则返回状态码412 Precondition Failed响应:

If-None-Match, 只有当If-Match的字段值跟请求资源的ETag值不匹配时服务器才接受请求,使用它可以获取最新的资源。
If-Modified-Since,请求的资源在指定日期后发生了更新服务器才接受请求,否则返回304 Not Modified(首部字段Last-Modified可以获取资源的更新日期),其作用与If-Match类似:

If-Unmodified-Since, 请求的资源在指定日期后未发生更新服务器才接受请求,否则返回412 Precondition Failed响应。
If-Range、Range, 请求的资源指定的ETag值或时间匹配时则可作为范围请求处理,否则返回全部资源:

10、Max-Forwards,通过TRACE或OPTIONS方法发送包含首部字段Max-Forwards的请求时,可以指定经过的服务器最大数目,当服务器收到收到值为0的请求时不再进行转发,直接返回响应,对此我们可以确定那台终点服务器的通信状态:


11、Proxy-Authorization, 接收到从代理服务器发来的认证质询时,客户端会发送包含该首部字段的请求,以告知认证所需要的信息,客户端与服务器之间的认证则使用首部字段Authorization。
12、Referer,告知服务器请求的原始资源的URI,告诉服务器我是从哪个页面链接过来的,服务器藉此可以获得一些信息用于处理,比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户点击我主页上的链接访问他的网站:

13、TE,告知服务器客户端能够处理响应的传输编码方式及相对优先级,与Accept-Encoding相像,但是用于传输编码。
14、User-Agent,标识客户端的设备、操作系统、浏览器等信息,例如Chrome浏览器的标识类似Mozilla/5.0 ... Chrome/79,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...) like Gecko 。默认的 User-Agent 通常会暴露爬虫的身份(该字段内为爬虫作者的电子邮件地址),导致被服务器拒绝访问(如返回 HTTP 403 错误)。通过修改 User-Agent,可以伪装成普通用户的浏览器,从而绕过限制。
响应首部字段:
1、Accept-Ranges, 范围请求可不可以被处理,Accept-Ranges: none表示不能处理范围请求,Accept-Ranges: bytes表示可以处理范围请求。
2、Age, 告知客户端资源缓存的时间,如Age: 600表示资源距上次请求已经过了600秒,代理创建响应时必须加上该首部字段。
3、ETag, 告知客户端实体标识,ETag值是服务器给每个资源分配的唯一性标识,如ETag: "82e323200c392ff89323acd12",当资源更新后其ETag值也会变化,如下。强ETag值是指实体发生细微变化就会改变ETag值,弱ETag值只有当资源发生根本改变产生差异时才会更新,弱ETag值会在字段值前加一个"W/",如ETag: W/usagi-1234。

4、Location, 提示浏览器重定向到另一个URI位置,该字段一般会配合3xx: Redirection的响应:

5、Proxy-Authenticate,将代理服务器所要求的认证信息发送给客户端,如Proxy-Authenticate: Basic realm="Usagidesign Auth"。服务器与客户端之间进行认证时,首部字段WWW-Authorization有着相同的作用。
6、Retry-After,告诉客户端在指定的秒数后或指定的时间(GMT格式)再次发起请求,主要配合状态码503 Service Unavailable响应或3xx Redirect响应使用。
7、Server, 告知客户端http服务器信息,如Server: Apache/2.2.6。
8、Vary, 对缓存进行控制,源服务器会向代理服务器传达关于本地缓存使用方法的命令:

9、WWW-Authorization,通知客户端适用于请求URI所指定资源的认证方案(Basic或Digest)和带参数提示的质询,状态码401 Unauthorized响应中肯定带有该首部字段,如WWW-Authorization: Basic realm="Usagidesign Auth"。
实体首部字段:
在请求和响应的HTTP报文中都含有与实体相关的首部:
1、Allow,当服务器收到不支持的方法请求时,会返回405 Method Not Found,并将其支持的方法写入到Allow首部字段中,如Allow: GET, HEAD。
2、Content-Encoding,告知客户端服务器对实体主体部分选用的内容编码方式,如Content-Encoding: gzip。
Content-Language, 告知客户端实体主体使用的语言,如Content-Language: zh-CN。
Content-Length, 实体主体部分的大小(字节),对实体主体进行内容编码传输时,不能使用该首部字段。
Content-Location, 指定报文主体返回资源对应的URI,比如,当返回的内容页面与实际请求的对象不同时,在该首部字段内写入URI。
Content-MD5,报文主体的MD5值,使用Base64编码。
Content-Range, 针对范围请求,告知客户端返回的实体的范围及整个实体的大小,如:Content-Range: bytes 5001-10000/10000。
Content-Type, 实体主体内对象的媒体类型,和首部字段Accept一样采用type/subtype形式,如Content-Type: text/html; charset=UTF-8。
3、Expires,告知客户端或缓存服务器资源失效时间,超出该时间后缓存服务器应该从源服务器获取该资源,如Expires: Wed, 23 May 2012 09:59:55 GMT。源服务器不希望缓存服务器缓存的时候可以将该字段写入与Date相同的时间值。
4、Last-Modified, 指明资源最新修改的时间,如Last-Modified: Wed, 23 May 2012 09:59:55 GMT。
非http/1.1标准首部字段
一些非http/1.1标准首部字段常用的有Cookie、Set-Cookie、Content-Dispositison、X-Frame-Options,其它还有X-XSS-Protection、DNT、P3P等。
1、Cookie、Set-Cookie首部用来为Cookie服务,Cookie数据由服务器端生成,发送给浏览器, 浏览器会将Cookie信息保存到某个目录下的文本文件内,下次再次请求该网址就会自动携带Cookie数据给服务器(cookie与域名天然相关)。Set-Cookie属于响应首部字段,由服务端设置,其包含了客户端需要存储的Cookie信息,Cookie属于请求首部字段,由客户端设置,其值为当前页面的cookie信息。cookie与指定的域名相关:浏览器向指定域名首次发送请求,服务端设置响应头Set-Cookie后,以后浏览器再向该域名请求数据时会自动附带cookie数据(通过请求头Cookie)。通过设置Cookie的Domain属性可扩展其域名生效范围,如服务端设置cookie的Domain=.example.com:该Cookie可在example.com及其所有子域(如api.example.com、app.example.com)间共享。关闭浏览器的话默认清空cookie,也可以设置cookie的过期时间,这样cookie会一直存在直到过期。
如下为一个包含cookie信息的响应报文:
HTTP/1.1 302 Found Date: Mon, 13 Nov 2017 00:46:23 GMT Server: Apache/2.2.22 (Win32) PHP/5.3.13 X-Powered-By: PHP/5.3.13 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: CHNCOOKUID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/my Set-Cookie: CHNCOOKSTA=Y; expires=Mon, 13-Nov-2017 00:46:22 GMT; path=/my Set-Cookie: PHPSESSID=ufhulbiv2oa0fcb1m06kfm7851; path=/ Set-Cookie: _beta_view_id=2; expires=Tue, 14-Nov-2017 00:46:25 GMT; path=/ Set-Cookie: CHNPOPUREG=yiyiyide%40163268.com; expires=Wed, 13-Dec-2017 00:46:25 GMT; path=/; domain=charmdate.com Set-Cookie: vpstat_c=4MA%3D%3D; expires=Tue, 14-Nov-2017 00:46:25 GMT; path=/ Set-Cookie: vpstat_l=8QzEwMDAwMA%3D%3D; expires=Tue, 14-Nov-2017 00:46:25 GMT; path=/ Set-Cookie: CHNCOOKUID=yiyiyide%40163268.com; expires=Wed, 14-Nov-2018 00:46:25 GMT; path=/ Set-Cookie: CHNCOOKSTA=Y; expires=Wed, 14-Nov-2018 00:46:25 GMT; path=/ Location: /my/overview.php Content-Length: 0 Keep-Alive: timeout=5, max=96 Connection: Keep-Alive Content-Type: text/html
Set-Cookie字段的属性必须包含赋予cookie的名称和值,其它属性有:
expires,cookie的有效期,不指定的话则默认为浏览器关闭为止,如果设置一个过去的时间,浏览器会立即删除该cookie。
domain,扩展cookie适用的域名, 比如设置Domain=.example.com后,所有子域名(比如a.example.com、b.example.com)也能访问该cookie,若不指定则默认为创建cookie的服务器的域名。
path,扩展cookie适用的路径,比如路径为/test,设置了path为/test,那么只有/test或者其子路径(如/test/sub)才会携带该cookie。如果未显示设置path的话,path的值默认为当前路径,比如路径为/test,那么path值为/test,即只有/test或其子路径(如test/sub)才会携带该cookie。如果路径为/test1,设置了path为/(即根路径),则/test1、/test1/sub、/test2都会携带该cookie。
secure,仅在https下才会启用cookie,防止cookie被抓包获取。指定secure属性的方式如:Set-Cookie: name=value, secure。
HttpOnly,开启后就无法通过JS脚本获得cookie(比如在JS中调用document.cookie),其主要目的是为防止跨站脚本攻击(XSS)对cookie信息的窃取。
SameSite,控制跨站请求是否自动携带cookie,设置为Strict的话表示完全禁止跨站(即仅同站点请求携带,可以防止跨站请求伪造CSRF),设置为Lax的话表示仅允许 “GET 类导航请求”(如链接跳转)携带,禁止 AJAX / 表单提交等跨站请求,设置为None表示允许跨站携带cookie。
在开发的时候,建议将上面cookie的属性显示的进行设置。
跨站请求伪造(CSRF)举例:用户访问了A网站登录成功(浏览器将登录状态保存在cookie中),当用户打开B网站后点击其中的一个按钮,而按钮点击的动作是访问A网站(自动附带登录状态cookie),这样B网站就伪装成了用户。开启SameSite是 CSRF 的核心防御手段,但一些老的浏览器不支持SameSite属性,所以另外还有一种使用CSRF Token的方式来进行CSRF防御,SameSite属于浏览器行为控制方案,CSRF Token属于服务器端验证方案,CSRF Token方案的具体做法详见Servlet这篇文章。
跨站脚本攻击/恶意脚本注入(XSS)举例:一个带文章评论的文章展示页面,攻击者在文章评论输入栏中提交了如下所示的内容,其他用户浏览该文章的时候前端会将前面攻击者的评论显示到评论区,而显示方法为直接使用document.getElementById('comment-list').innerHTML="攻击者评论"来显示评论内容,而浏览器会将攻击者评论中的<script>视为脚本并执行,这样就会将用户的cookie上传到了攻击者的服务器中。

防御XSS的三种方法:①、将用户的输入(表单、URL参数、评论等)进行合法校验,过滤掉<script>、eval()、onclick等恶意脚本片段。 ②、将用户内容中的特殊字符转义,可以使用框架自带的转义功能,如 React 的 JSX 自动转义。③、启用内容安全策略(CSP),如下所示,后端页面接口通过设置Content-Security-Policy响应头来开启CSP(也可以通过html中的meta标签来开启CSP),限制前端资源加载和脚本执行范围,script-src 'self' https://cdn.trusted.com表示只允许执行与当前页面域名相同的外部JS文件和指定域名的外部JS,除了它们外,一切内联脚本会被禁止执行,default-src 'self'表示所有未被单独指定的资源类型(图片、CSS、AJAX请求等),只允许从当前域名加载,所以即使攻击者恶意脚本侥幸被执行了,其视图加载外部服务器的图片(本质是发送窃取的Cookie)也会被浏览器拦截 )。将CSP指令设置成'unsafe-inline'的话(比如script-src 'unsafe-inline')表示允许内联脚本 / 样式(不推荐,相当于是关闭了CSP 核心防护)。

“内联脚本” 指的是不通过外部文件 <script src="..."> 引入, 直接嵌入在 HTML 中的 JavaScript 代码。如下所示的三种类型都属于内联脚本,都会被CSP默认禁止执行:
①、HTML文件中 <script> 标签内的所有代码
②、on开头的事件属性(如 onclick、onload、onerror 等)中包含的JavaScript代码
③、javascript: 伪协议(如a标签在被点击时不是跳转而是执行JS代码:<a href="javascript:alert('hello!')">点击我</a>)
CSP限制的是可执行代码或资源加载,如内联脚本、内联样式、外部脚本 / 样式的来源,HTML 元素的普通属性(如 input 的 value)仅用于存储数据,不会被浏览器当作 “可执行代码” 处理,因此不会受CSP限制,如下所示在 form 表单中通过 th:value = "${csrfToken}" 将隐藏输入框的 value 属性值设置为user对象的name,不会受到 CSP的限制:
<form action = "demo.php" method = "POST"> <input type = "hidden" name = "_name" th:value = "${user.name}"><br> </form>
由于开启了CSP后会禁止内联JS的执行,所以一般都是将JS放到外部文件中来执行(JS地址域名与页面域名相同或者在白名单中)。CSP还提供了"hash"和"nonce"两种安全机制,允许在不开启 'unsafe-inline' 的情况下,放行特定内联脚本:hash机制是在Content-Security-Policy响应头添加要放行JS内容的哈希值,JS内容哈希匹配的内联脚本会被允许执行,攻击者的XSS脚本因为没有改哈希值所以不会被执行,如下图1所示。nonce机制是在Content-Security-Policy响应头中添加一个随机值(每次请求该值随机生成),同时在需要被放行的JS脚本中添加该随机值,攻击者的XSS脚本内容因为没有该随机值所以其不会被执行,如下图2所示。 hash机制适合静态脚本(代码内容写死,因为其内容固定,所以哈希值固定不变),noce机制适合动态脚本(脚本实际内容动态变化,比如里边包含注入的变量,该变量值会随用户的不同而变化)。

2、Content-Dispositison用来指示如何显示附加的文件,即设置Content-Disposition告诉浏览器下载文件的名称和是否在浏览器中内嵌显示,如:
Content-disposition: inline; filename=1502849449726.jpg表示浏览器内嵌显示一个文件。
Content-disposition: attachment; filename=1502849449726.xlsx表示弹出下载提示对话框来下载文件。
3、X-Frame-Options属于http响应首部,用来控制网站内容在其它web网站的Frame标签内的显示,其主要目的是为了防止点击劫持(clickjacking)攻击,如将其设为字段值DENY的话就是拒绝,页面不能被嵌入到任何iframe或frame中,SAMEORIGIN则为页面只能被本站页面嵌入到iframe或者frame中(比如当指定http://hackr.jp/sample.html页面为SAMEORIGIN时,hackr.jp上所有页面的frame都被允许可加载该页面,其它域名的页面就不行),ALLOW-FROM:页面允许frame或frame加载。
浙公网安备 33010602011771号