各浏览器对于以下各种非标准 HTTP 报头的兼容情况可以参考 Can I Use 站点上的相关内容。
请求头
DNT
请求某个网页应用程序停止跟踪某个用户。在 Firefox 浏览器中,相当于 X-Do-Not-Track
协议头字段(自 Firefox 4.0 测试(Beta)11 版开始支持)。 Safari 和 IE 9 也支持这个字段。
DNT: 1 (启用)
DNT: 0 (禁用)
注:目前 DNT
在 W3C 还未正式成为标准,参考:Tracking Preference Expression (DNT)
X-Forwarded-For
一个事实标准,用于标识某个通过超文本传输协议代理或负载均衡连接到某个网页服务器的客户端的原始互联网地址。
X-Forwarded-For: client1, proxy1, proxy2
X-Forwarded-For: 129.78.138.66, 129.78.64.10
在 Java Servlet 中获取客户端 IP 地址的参考代码:
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ServletUtils {
private static final Logger log = LoggerFactory.getLogger( ServletUtils.class );
private static final String[] PROXY_REMOTE_IP_ADDRESS;
static {
// read2Array 将文件中的内容读出作为数组,
// 每个数组中的元素中文件中的一行,
// 若文件不存在时返回空数组
String[] proxyRemoteHeaders = read2Array( Thread.currentThread().getContextClassLoader() , "remote-ip-headers" );
if ( proxyRemoteHeaders.length == 0 ) {
proxyRemoteHeaders = read2Array( ServletUtils.class , "remote-ip-headers-default" );
}
PROXY_REMOTE_IP_ADDRESS = proxyRemoteHeaders;
log.info( "Remote address headers: {}" , Arrays.toString( PROXY_REMOTE_IP_ADDRESS ) );
}
/**
* 获取请求的客户端的 IP 地址。若应用服务器前端配有反向代理的 Web 服务器,
* 需要在 Web 服务器中将客户端原始请求的 IP 地址加入到 HTTP header 中。
*
* Web 服务器反向代理中用于存放客户端原始 IP 地址的 Http header 名字,
* 默认值为根据优先级为 "X-Forwarded-For" 和 "X-Real-IP",
* 若有需要使用其他的 HTTP header,需要在 classpath 的 remote-ip-headers
* 文件中添加所需要的 HTTP header 名字,根据优先级依次在该文件中增加数据,
* 格式为每行一个 headers 名称。
*
* @param request HTTP 请求
* @return 远程客户端的 IP 地址
*/
public static String getRemoteIp(HttpServletRequest request) {
for ( int i = 0; i < PROXY_REMOTE_IP_ADDRESS.length; i++ ) {
String ip = request.getHeader( PROXY_REMOTE_IP_ADDRESS[i] );
if ( StringUtils.isNotBlank(ip) ) {
return getRemoteIpFromForward( ip );
}
}
return request.getRemoteAddr();
}
/**
* 从 HTTP Header 中根据反向代理请求头的规范截取客户端连接 IP 地址。
* 如果经过多次反向代理,在相应的请求头中获得的是以“,<SP>”
* 分隔 IP 地址链,第一段则为客户端 IP 地址。
*
* @param xforwardIp
* @return 通过代理服务器后获取的客户端 IP 地址
*/
private static String getRemoteIpFromForward(String xforwardIp) {
int commaOffset = xforwardIp.indexOf(',');
if (commaOffset < 0) {
return xforwardIp;
}
return xforwardIp.substring(0, commaOffset);
}
}
注:在 RFC 7239 中被 Forwarded
请求头取代。
X-Forwarded-Host
一个事实标准,用于请求客户端原始 Host 的 HTTP 请求头,由于经过反向代理(负载均衡服务器)原始的 Host 值可能与实际值不同。
X-Forwarded-Host: en.wikipedia.org:80
X-Forwarded-Host: en.wikipedia.org
注:在 RFC 7239 中被 Forwarded
请求头取代。
X-Forwarded-Proto
一个事实标准,用于标识某个超文本传输协议请求最初所使用的协议,因为,在反向代理(负载均衡)上,即使最初发往该反向代理的请求类型是安全的超文本传输协议(HTTPS),该反向代理也仍然可能会使用超文本传输协议(HTTP)来与网页服务器通信。谷歌客户端在与谷歌服务器通信时会使用该协议头的一个替代形式(X-ProxyUser-Ip)。
X-Forwarded-Proto: https
注:在 RFC 7239 中被 Forwarded
请求头取代。
X-Http-Method-Override
请求某个网页应用程序使用该协议头字段中指定的方法(一般是 PUT 或 DELETE)来覆盖掉在请求中所指定的方法(一般是 POST)。当某个浏览器或防火墙阻止直接发送 PUT 或 DELETE 方法时(注意,这可能是因为软件中的某个漏洞,因而需要修复,也可能是因为某个配置选项就是如此要求的,因而不应当设法绕过),可使用这种方式。
X-HTTP-Method-Override: DELETE
在开发 REST 风格的 Web 服务时,应将 X-Http-Method-Override
考虑至实现中。在 Spring MVC 中有个通过 _method
请求参数实现的过滤器 HiddenHttpMethodFilter,可以参照这个过滤器去实现一个用于处理 X-Http-Method-Override
请求头的过滤器。
X-Requested-With
主要用于标识 Ajax 及可扩展标记语言请求。大部分的 JavaScript 框架会发送这个字段,且将其值设置为 XMLHttpRequest。
X-Requested-With: XMLHttpRequest
响应头
Timing-Allow-Origin
参考:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin
用于指定特定站点,以允许其访问 Resource Timing API 提供的相关信息,否则这些信息会由于跨源限制将被报告为零。
Timing-Allow-Origin: *
Timing-Allow-Origin: [, ]*
Strict-Transport-Security
一种 HSTS(HTTP Strict Transport Security, HTTP 严格传输安全)策略,强制客户端(如浏览器)使用 HTTPS 与服务器创建连接。服务器开启 HSTS 的方法是,当客户端通过 HTTPS 发出请求时,在服务器返回的超文本传输协议响应头中包含 Strict-Transport-Security 字段。非加密传输时设置的 HSTS 字段无效。
比如,https://example.com/ 的响应头含有 Strict-Transport-Security: max-age=31536000; includeSubDomains
。这意味着两点:
- 在接下来的一年(即 31536000 秒)中,浏览器只要向 example.com 或其子域名发送 HTTP 请求时,必须采用 HTTPS 来发起连接。比如,用户点击超链接或在地址栏输入 http://www.example.com/,浏览器应当自动将 http 转写成 https,然后直接向 https://www.example.com/ 发送请求。
- 在接下来的一年中,如果 example.com 服务器发送的 TLS 证书无效,用户不能忽略浏览器警告继续访问网站。
Strict-Transport-Security: max-age=31536000; includeSubDomains
安全提示:若网站是 HTTPS 时应设置该响应头,以避免通过 HTTP 发起请求后在服务器端进行 302 跳转至 HTTPS,这样存在中间人攻击潜在威胁,跳转过程可能被恶意网站利用来直接接触用户信息,而不是原来的加密信息。更多的信息参考 MDN 中相关的内容。
友情提示:一旦设置了 Strict-Transport-Security
头后,在所设置的过期时间内当前域名就必须使用 HTTPS 协议进行访问,无法再通过 HTTP 访问,如果还需要通过 HTTP 访问只能更换域名(在服务端重定向至 HTTP 的新域名),使用时请注意。
注:已在 RFC 6797 中标准化。
X-Accel-Redirect
Nginx 后端响应头
参考:https://www.nginx.com/resources/wiki/start/topics/examples/x-accel
当客户端发起请求下载某个文件时,因为并没有 X-Accel-Redirect
头,Web 服务器并不会立刻就把文件输出给客户端;而是将这个请求交给后端的程序语言,程序语言验证认为该客户端可以下载这个文件,就写出相应的 X-Accel-Redirect
头并结束处理;X-Accel-Redirect
头返回时经过前端的 Web 服务器,Web 服务器检查到这个头之后,才把文件输出到客户端。
如果客户端伪造一个 X-Accel-Redirect
头来读取呢?当然也是不能下载的,因为web服务器只认识后端发来的 X-Accel-Redirect
头,客户端发来的不算。
Nginx 还有很多 X-Accel
相关的参数,比如速度、缓冲、字符集等,参考 Nginx 的 X-Accel 文档。
X-Accel-Redirect: /mp3/1.mp3
X-Content-Type-Options
即使给一个 html 文档指定 Content-Type 为“text/plain”,在 IE8 中这个文档依然会被当做 HTML 来解析。利用浏览器的这个特性,攻击者甚至可以让原本应该解析为图片的请求被解析为 JavaScript。通过下面这个响应头可以禁用浏览器的类型猜测行为。这个响应头的值只能是 nosniff,可用于 IE8+ 和 Chrome。
X-Content-Type-Options: nosniff
X-Frame-Options
点击劫持(Clickjacking)保护。
-
deny
表示在 frame 中页面不呈现 -
sameorigin
表示在 frame 中如果源地址不一致时页面不呈现 -
allow-from
表示允许指定的地址 -
allowall
非标准,允许任一地址
X-Frame-Options: deny
注:已在 RFC 7034 中标准化。
X-XSS-Protection
参考:https://blogs.msdn.microsoft.com/ieinternals/2011/01/31/controlling-the-xss-filter/
跨站脚本攻击 (XSS)过滤器,有以下几种配置:
-
0
禁用 XSS 保护 -
1
启用 XSS 保护 -
1; mode=block
启用 XSS 保护,并在检查到 XSS 攻击时,停止渲染页面(例如 IE8 中,检查到攻击时,整个页面会被一个 # 替换)
X-XSS-Protection: 1; mode=block
参考
- 一些安全相关的 HTTP 响应头, https://imququ.com/post/web-security-and-response-header.html
- Content Security Policy 介绍,https://imququ.com/post/content-security-policy-reference.html
- HTTP 头字段列表,https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5%E5%88%97%E8%A1%A8
- List of HTTP header fields, https://en.wikipedia.org/wiki/List_of_HTTP_header_fields