中国卓越技术团队访谈录读者调查,2022年采访嘉宾由你决定! 了解详情
写点什么

最全 HTTP 安全响应头设置指南

  • 2019 年 7 月 22 日
  • 本文字数:4500 字

    阅读完需:约 15 分钟

最全HTTP安全响应头设置指南

销售“安全记分卡”的公司正在崛起,并已开始成为企业销售的一个因素。这些公司组合使用 HTTP 安全报头和 IP 信誉来进行评级。不过,在很大程度上,公司的得分取决于对外开放网站上设置的安全响应报头。本文介绍了常用的安全响应报头及对应的推荐安全值,并给出了示例。


销售“安全记分卡”的公司正在崛起,并已开始成为企业销售的一个因素。我从客户那里了解到,他们对从评级低的供应商那里的采购很不放心,至少有案例表明,他们依据最初的评级改变了采购决策。


我调查了这些评级公司是如何计算公司安全性得分的,结果发现他们组合使用了 HTTP 安全报头和 IP 信誉。


IP 信誉基于的是黑名单和垃圾邮件列表,再加上公共 IP 所有权数据。只要你的公司没有垃圾邮件,并且能够快速检测和阻止恶意软件感染,那么通常这些软件应该就是干净的。HTTP 安全报头使用的计算方式与Mozilla Observatory的工作方式类似。


因此,对于大多数公司来说,在很大程度上,他们的得分取决于对外开放的网站上设置的安全响应报头。


设置正确的响应报头可以快速实现(通常不需要进行大量测试),并能提高网站的安全性,现在还可以帮助我们赢得具有安全意识的客户。


我对这种测试方法的价值以及这些公司提出的过高的定价方案持怀疑态度。我不认为它与真正的产品安全性有那么大的关联。然而,这无疑增加了设置响应报头并维护其正确性的重要性,值得为此投入时间。


在本文中,我将介绍常用的评估响应报头,及每个报头的推荐安全值,并给出一个响应报头设置的示例。在本文的最后,还将给出常见的应用程序和 Web 服务器的设置示例。


重要的安全响应报头

Content-Security-Policy(CSP)

CSP 通过指定允许加载哪些资源的形式,来防止跨站脚本注入。在本文所列的安全响应报头中,正确地设置和维护 CSP,可能是最耗时的,也是最容易出现风险的。在开发 CSP 的过程中,要谨慎充分地测试它——以“合法”的方式阻塞站点使用的内容源会破坏站点的功能。


创建 CSP 初稿的一个很好的工具是Mozilla实验室的CSP浏览器扩展。在浏览器中安装此扩展程序,首先充分地浏览要为其设置 CSP 的站点,然后在站点中使用生成的 CSP。理想情况下,还可以重构 JavaScript,使其没有残留的任何内联脚本,从而使我们可以删除“unsafe inline”指令设置。


CSP 的指令设置可能比较复杂,也很混乱,因此,如果你想更深入的了解 CSP,请访问其官方网站


一个好的 CSP 开始可能是如下这样的(在真正的站点上使用时,可能需要进行大量的修改)。在包含该站点的每个部分中都添加域名。


# 默认情况下,仅允许访问当前站点的内容# 允许访问当前站点和imgur.com的图片资源# 不允许访问Flash、Java等对象# 仅允许访问当前站点的脚本# 仅允许访问当前站点的样式# 仅允许嵌入当前站点的内嵌# 将<base>标记中的URL限制在当前站点# 表单仅允许提交到当前站点Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';
复制代码


Strict-Transport-Security(HSTS)

该响应报头告诉浏览器,只能通过 HTTPS 访问网站——如果网站启用过 HTTPS,它将会一直生效。如果使用子域名,还建议在任何使用过的子域名对此加以强制。


Strict-Transport-Security: max-age=3600; includeSubDomains
复制代码


X-Content-Type-Options

该响应报头确保浏览器遵守应用程序设置的 MIME 类型。这有助于防止某些类型的跨站脚本注入攻击。


它还能减少浏览器“猜测”某些内容不正确时的意外应用程序行为,例如,当开发人员将某个页面标记为“HTML”,但浏览器认为它更像 JavaScript,并试图将其渲染为 JavaScript 时。该响应报头能确保浏览器始终遵守服务端设置的 MIME 类型。


X-Content-Type-Options: nosniff
复制代码


Cache-Control(缓存控制)

这个响应报头比其他的要稍微复杂一些,因为我们可能需要根据内容类型的不同而使用不同的缓存策略。


任何具有敏感数据的页面,如用户页面或客户结算页面,都应该设置成无缓存。其中一个原因是,防止共享计算机上的某个人按回退按钮或浏览历史记录又能查看到个人信息。


但是,对于像静态资产(图像、CSS 文件和 JS 文件)等很少变更的页面,很适合使用缓存。既可以通过逐页设置的方式来实现,也可以通过在服务端配置使用正则表达式的方式来实现。


#  默认情况不使用缓存 Header set Cache-Control no-cache
# 静态资产设置成缓存1天<filesMatch ".(css|jpg|jpeg|png|gif|js|ico)$"> Header set Cache-Control "max-age=86400, public"</filesMatch>
复制代码


Expires(过期时间)

该响应报头能设置当前请求缓存的过期时间。如果设置了 Cache-Control 的 max-age 响应报头,它将会被忽略,因此,在不考虑使用 Cache-Control 而进行本地缓存测试时,才设置它。


为了安全起见,我们假定浏览器不应该缓存任何内容,因此,我们可以把过期时间设置为一个总表示过期的数值。


Expires: 0
复制代码


X-Frame-Options

该响应报头用来表明站点是否允许在 iFrame 中展示。


如果恶意站点将我们的网站嵌套在 iFrame 中,那么恶意站点就可以通过运行一些 JavaScript 来执行点击劫持攻击,这些 JavaScript 能够捕获 iFrame 上的鼠标点击事件,然后代表用户与该站点进行交互(不必单击需要单击它们的地方!)。


应该始终将它设置为 deny(拒绝),除非特别需要使用内嵌,在这种情况下,应将其设置为 same-origin(同源)。如果需要在页面中内嵌其他的站点,也可以在此处以白名单的形式列举其他的域名。


还应该注意的是,这个响应报头已经被 CSP 的 frame-ancestors 指令所取代。目前,我仍然建议设置该响应报头来兼容不同的工具,但将来它可能会被逐步淘汰。


X-Frame-Options: deny
复制代码


Access-Control-Allow-Origin

通过该响应报头可以告诉浏览器,允许哪些其他站点的前端 JavaScript 代码对页面发出请求。除非需要设置此响应报头,否则通常默认值就是正确的设置。


例如,如果站点 A 使用了一些 JavaScript,该 JavaScript 想要向站点 B 发出请求,那么站点 B 必须使用指定了允许站点 A 发出此请求的报头来提供响应。如果需要设置多个源,请参见MDN上的详情介绍页面


这可能有点难以理解,因此,我画了一个图表来说明这个响应报头是如何工作的:



Access-Control-Allow-Origin 对应的数据流


Set-Cookie

确保 cookie 仅能通过 HTTPS(加密)传送,并且不能通过 JavaScript 访问。如果站点也支持 HTTPS(站点应该支持 HTTPS),那么就只能发送 HTTPS cookie。我们通常需要设置如下标志:


  • Secure

  • HttpOnly


一个定义 Cookie 的示例:


Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
复制代码


请参阅Mozilla文档中的 cookies 部分以了解更多相关信息。


X-XSS-Protection

该响应报头用来指示浏览器停止执行跨站脚本攻击检测。一般来说,设置它的风险很低,但在投入生产前仍需要进行测试。


X-XSS-Protection: 1; mode=block
复制代码


Web 服务器的配置示例

通常,最好在服务器配置中添加站点范围内的响应报头。在此,cookie 是一个例外,因为它们通常是在应用程序内定义的。


在将任何响应报头添加到站点之前,我建议首先检查 Observatory 或手动查看响应报头,以查看已经设置了哪些响应报头。有些框架和服务器会自动设置其中一些响应报头,因此,我们只需设置我们需要的或想要变更的响应报头即可。


Apache 配置

.htaccess 中的 Apache 设置示例:


<IfModule mod_headers.c>    ## CSP    Header set Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';
## 通用的安全响应报头 Header set X-XSS-Protection: 1; mode=block Header set Access-Control-Allow-Origin: http://www.one.site.com Header set X-Frame-Options: deny Header set X-Content-Type-Options: nosniff Header set Strict-Transport-Security: max-age=3600; includeSubDomains
## 缓存策略 # 默认情况下不使用缓存 Header set Cache-Control no-cache Header set Expires: 0
# 设置静态资产缓存1天 <filesMatch ".(ico|css|js|gif|jpeg|jpg|png|svg|woff|ttf|eot)$"> Header set Cache-Control "max-age=86400, public" </filesMatch>
</IfModule>
复制代码


Nginx 设置

## CSPadd_header Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';
## 通用的安全响应报头
add_header X-XSS-Protection: 1; mode=block;add_header Access-Control-Allow-Origin: http://www.one.site.com;add_header X-Frame-Options: deny;add_header X-Content-Type-Options: nosniff;add_header Strict-Transport-Security: max-age=3600; includeSubDomains;
## 缓存策略
** 默认不使用缓存**
add_header Cache-Control no-cache;add_header Expires: 0;
**设置静态资产缓存1天**
location ~* \.(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ { try_files $uri @rewriteapp; add_header Cache-Control "max-age=86400, public";}
复制代码


应用程序级的响应报头设置

如果我们没有访问 Web 服务器的权限,或者需要设置复杂的响应报头,那么我们就可能需要在应用程序内设置这些响应报头了。这通常可以在整个站点的框架中间件中实现,也可以在每次响应的基础上进行一次性的报头设置。


为了简便起见,在示例中,只包含了一个响应报头。所需的全部响应报头都是以相同的方式通过该方法来添加的。


Node 及 express:

添加一个全局挂载路径:


app.use(function(req, res, next) {    res.header('X-XSS-Protection', 1; mode=block);        next();});
复制代码


Java 及 Spring:

我没有太多的 Spring 实践经验,但Baeldung对在 Spring 中如何设置响应报头提供了很好的指导。


PHP:

我对各种 PHP 框架不是很熟悉。查找了能够处理请求的中间件。对于单个响应,它的设置非常简单。


header("X-XSS-Protection: 1; mode=block");
复制代码


Python 及 Django

Django 包含可配置的安全中间件,通过该中间件来处理所有响应报头的设置。首先启用它们。


对于特定页面,可以将响应视为字典。Django 有一个处理缓存的特殊方法,如果试图以这种方式设置缓存响应报头,那么就应该调研后再使用。


response = HttpResponse()response["X-XSS-Protection"] = "1; mode=block"
复制代码


总结

设置响应报头相对来说比较简单快捷。在数据保护、跨站脚本注入和点击劫持方面,站点安全性将会有相当大的提高。


还可以确保我们不会因为依赖此信息的公司安全评级而失去未来的业务交易。这种做法似乎越来越多,我希望在未来几年,它能继续在企业销售中发挥作用。


如果以上有所遗漏,你认为还应该包含其他的安全响应报头,请留言回复。


英文原文:https://nullsweep.com/http-security-headers-a-complete-guide


2019 年 7 月 22 日 18:414696
用户头像

发布了 158 篇内容, 共 67.1 次阅读, 收获喜欢 417 次。

关注

评论 1 条评论

发布
用户头像
译者是infoQ官方人员吗?
2019 年 07 月 25 日 16:47
回复
没有更多了
发现更多内容

架构师培训 -05 缓存、消息和负载均衡

刘敏

架构师训练营 第五周 个人感想

且听且吟

再谈大型网站技术应用——上篇

Jerry Tse

网站架构 分布式系统 极客大学架构师训练营 作业

架构师训练营 Week5作业

平淡人生

LeetCode 3. Longest Substring Without Repeating Characters

liu_liu

算法 Leetc

架构师第五周作业

suke

极客大学架构师训练营

第5周总结

远方

一致性哈希算法&Java实现

Lane

极客大学架构师训练营

架构师训练营第五周学习总结

fenix

Week05 学习心得 - 技术选型

极客大学架构师训练营

架构师第五周总结

suke

极客大学架构师训练营

第5周作业

andy

架构师训练营第五周作业

James-Pang

极客大学架构师训练营

免费的GPU,还有全系列的OpenJDK

孙苏勇

Java 学习 gpu Openjdk Colab

区块链大规模应用“补位”开始了

CECBC

第五周学习总结

李白

week5. 课后作业

dj_cd

架构师训练营第五周作业

fenix

一致性哈希算法分析与go语言实现

superman

极客大学架构师训练营 一致性Hash算法 Go 语言

架构师训练营第 05周—— 练习

李伟

第五周学习总结

CP

架构师训练营-第五章-一致性hash算法

而立

极客大学架构师训练营

第五周作业

CP

架构师训练营Week5总结

平淡人生

一致性哈希算法简单实现

Jerry Tse

源码 极客大学架构师训练营 作业 一致性哈希

架构师训练营第五周总结

James-Pang

极客大学架构师训练营

第5周:作业一

远方

第5周总结

andy

第5周-总结

Dawn

LeetCode 12. Integer to Roman

liu_liu

算法 LeetCode

第五周作业

倪惠华

撑起瞬时千亿交易额的云数据库是怎么炼成的?

撑起瞬时千亿交易额的云数据库是怎么炼成的?

最全HTTP安全响应头设置指南-InfoQ