使用 HTTP 标头保护您的网站

2025-05-27

使用 HTTP 标头保护您的网站

Mozilla 的 Observatory通过教导开发人员、系统管理员和安全专家如何安全地配置他们的网站来帮助网站。

让我们来看看 Observatory 对一个相当简单的Static Buildpack应用程序给出的分数,https://2017.keeprubyweird.com

考试成绩

测试 经过 分数 解释
内容安全策略 -25 内容安全策略(CSP)标头未实现
曲奇饼 0 未检测到任何 Cookie
跨域资源共享 0 内容无法通过跨域资源共享 (CORS) 文件或标头看到
HTTP 公钥固定 0 HTTP 公钥固定(HPKP)标头未实现(可选)
HTTP 严格传输安全 -20 HTTP 严格传输安全 (HSTS) 标头未实现
重定向 0 初始重定向到同一主机上的 https,最终目的地是 https
推荐人政策 0 Referrer-Policy 标头未实现(可选)
子资源完整性 0 子资源完整性 (SRI) 未实现,但所有脚本均从相似的来源加载
X-Content-Type-选项 -5 X-Content-Type-Options 标头未实现
X-Frame-选项 -20 X-Frame-Options(XFO)标头未实现
X-XSS 保护 -10 X-XSS-Protection 标头未实现

尽管我们使用 Heroku 的自动证书管理功能轻松为域名获取 SSL 证书,但我们的总体评分仅为 F,20/100。我们将逐一分析每个失败的测试,找出失败的原因,并尝试修复它们。

内容安全策略 (CSP)

这里的故障是“CSP 标头未实现”,当我们查看链接的安全指南时,我们发现 CSP 使我们能够控制网站上引用的脚本和资源的加载位置。对于 Keep Ruby Weird 来说,这意味着字体、多个外部图片源以及一些分析源。

CSP 为我们提供了几个严格级别:

  • default-src <source>、、、等等script-src <source>object-src <source>这些限制了各类资源的来源。
    • https:将指定类型的资源或所有资源限制为仅 HTTPS
    • https://example.com将资源限制在此域内。可以为同一*-src指令提供多个此类来源。
    • 'self'意味着资源只能从当前主机加载,对于诸如的相关资源很有用<script src="/index.js">
    • 请参阅MDN 上的CSP: default-src了解完整选项。
  • 默认情况下,标Content-Security-Policy头不允许<script>使用带有内联代码的标签。带有 的标签src则允许使用。可以通过添加 来禁用此'unsafe-inline'功能,这会降低我们网站的安全性。您还可以指定nonce这些脚本内容的 s 或 SHA 值,以允许它们执行。
  • frame-ancestors 'none'防止您的网站被加载到 iframe 中并被用于点击劫持攻击。如果您确实需要在 iframe 中显示您的网站,您可以指定 URL。

为了实现我们的目的,我们希望能够使用自托管资源、来自 Twitter 和 AWS 的图片、来自 Google 和 Twitter 分析的脚本,以及来自 Google Fonts 的样式表和字体条目。我们还需要重新定义 'self'一些指令,因为除非未指定选项,否则它们不会恢复为默认值。例如,我们没有指定 ,object-src因此它会恢复为default-src的值'self'

Content-Security-Policy: default-src 'self';
                         script-src https://static.ads-twitter.com https://www.google-analytics.com;
                         img-src 'self' https://s3.amazonaws.com https://twitter.com https://pbs.twimg.com;
                         font-src 'self' https://fonts.gstatic.com;
                         style-src 'self' https://fonts.googleapis.com;
                         frame-ancestors 'none';
Enter fullscreen mode Exit fullscreen mode

我们可以将其添加到我们的 static.json 中作为所有路径的标头集合的一部分:

# ...
"headers": {
  "/**": {
    "Content-Security-Policy": "default-src 'self'; script-src https://static.ads-twitter.com https://www.google-analytics.com; img-src 'self' https://s3.amazonaws.com https://twitter.com https://pbs.twimg.com; font-src 'self' https://fonts.gstatic.com; style-src 'self' https://fonts.googleapis.com; frame-ancestors 'none';"
  }
}
Enter fullscreen mode Exit fullscreen mode

当我们添加或删除外部资源时,我们需要更新此集合,否则我们的用户将在浏览器的控制台中看到错误,并且资源将不可用。

HTTP 严格传输安全 (HSTS)

我们未能通过此测试,原因基本相同:“未实现 HTTP 严格传输安全 (HSTS) 标头”。

HSTS 会告知浏览器我们的网站只能通过 HTTPS 访问。查看 HSTS 安全指南,我们发现 HSTS 提供了几个非排他性标志:

  • max-age=<seconds>用户代理重定向到 HTTPS 的时间长度(以秒为单位)。这会告诉浏览器“一旦您看到此信息,就假设所有到此域名的请求都将在这段时间内通过 HTTPS 进行”。Mozilla 建议使用 2 年(即630720002 秒)。此标志是必需的。
  • includeSubDomains用户代理是否应升级子域名的请求。除非您有理由不在所有子域名上使用 SSL,否则您可能需要此功能。即使您目前没有子域名,我也建议您这样做。
  • preload如果您启用此标记,并在Chrome HSTS 预加载列表中注册了您的域名,那么浏览器甚至无需查看此标头即可强制执行 HTTPS 请求。此功能很有用,但请自行选择,因为您需要在预加载列表中查找域名,勾选一些复选框并提交,才能注册您自己的域名。注册过程非常简单,我们将在这里进行操作。
# ...
"headers": {
  "/**": {
    "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload"
  }
}
Enter fullscreen mode Exit fullscreen mode

X-Content-Type-选项

此标头告知浏览器,如果服务器指示的 MIME 类型不正确,则不要加载脚本和样式表。启用此功能很有用。

# ...
"headers": {
  "/**": {
    "X-Content-Type-Options": "nosniff"
  }
}
Enter fullscreen mode Exit fullscreen mode

X-Frame-选项

此标头可防止您的网站在 iframe 中加载。它有助于防止“点击劫持”攻击。它与 Content-Security-Policy 提供的保护相同frame-ancestors 'none',但增加了对旧版浏览器的支持。如果您确实需要在网站其他页面的 iframe 中显示您的网站,则可以改用此SAMEORIGIN选项。

# ...
"headers": {
  "/**": {
    "X-Frame-Options": "DENY"
  }
}
Enter fullscreen mode Exit fullscreen mode

X-XSS 保护

此标头可防止跨站点脚本(XSS)攻击。它提供与 Content-Security-Policy 类似的保护,但同样保护旧版浏览器。

# ...
"headers": {
  "/**": {
    "X-XSS-Protection": "1; mode=block"
  }
}
Enter fullscreen mode Exit fullscreen mode

整合起来

将此标题块添加到我们的 static.json 中,可将天文台的分数从 F 提高到 A。

"headers": {
  "/**": {
    "Content-Security-Policy": "default-src 'self'; script-src https://static.ads-twitter.com https://www.google-analytics.com 'sha256-q2sY7jlDS4SrxBg6oq/NBYk9XVSwDsterXWpH99SAn0='; img-src 'self' https://s3.amazonaws.com https://twitter.com https://pbs.twimg.com; font-src 'self' https://fonts.gstatic.com; style-src 'self' https://fonts.googleapis.com; frame-ancestors 'none';",
    "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload",
    "X-Content-Type-Options": "nosniff",
    "X-Frame-Options": "DENY",
    "X-XSS-Protection": "1; mode=block"
  }
}
Enter fullscreen mode Exit fullscreen mode

当我们加载浏览器时,一切看起来都正常!不幸的是,我们漏掉了一件事,我们可以在控制台中看到。

拒绝执行内联脚本,因为它违反了以下内容安全策略指令:“script-src https://static.ads-twitter.com https://www.google-analytics.com ”。启用内联执行需要“unsafe-inline”关键字、哈希值(“sha256-q2sY7jlDS4SrxBg6oq/NBYk9XVSwDsterXWpH99SAn0=”)或随机数(“nonce-...”)。

尽管我们在 script-src 中添加了https://www.google-analytics.com,但由于它是以内联脚本的形式加载的,因此我们需要明确允许它运行。错误消息很贴心地提供了几个选项:“需要‘unsafe-inline’关键字、哈希值(‘sha256-q2sY7jlDS4SrxBg6oq/NBYk9XVSwDsterXWpH99SAn0=’)或随机数(‘nonce-...’)才能启用内联执行。”

'unsafe-inline'听起来,嗯,不安全,所以我们跳过这个。Nonce 是一次性使用的数字,允许内联脚本运行。Nonce 可以很安全,但由于我们讨论的是静态页面,这超出了我们的讨论范围。错误消息中提供的哈希值是内联代码块内容的实际 SHA-256 和,比其他选项更安全。它可以阻止攻击者更改 Google Analytics(分析)内联脚本的内容,这使得它比不受保护的内联脚本更安全。与更改外部依赖项一样,如果我们更改该脚本标签,我们也需要更改 SHA-256 和。

"Content-Security-Policy": "default-src 'self'; script-src https://static.ads-twitter.com https://www.google-analytics.com 'sha256-q2sY7jlDS4SrxBg6oq/NBYk9XVSwDsterXWpH99SAn0='; img-src 'self' https://s3.amazonaws.com https://twitter.com https://pbs.twimg.com; font-src 'self' https://fonts.gstatic.com; style-src 'self' https://fonts.googleapis.com; frame-ancestors 'none';"
Enter fullscreen mode Exit fullscreen mode

我们已经添加了 SHA 总和,现在 Google Analytics 已全部设置完毕!

结果

测试 经过 分数 解释
内容安全策略 +5 内容安全策略 (CSP) 实施无需'unsafe-inline''unsafe-eval'
曲奇饼 0 未检测到任何 Cookie
跨域资源共享 0 内容无法通过跨域资源共享 (CORS) 文件或标头看到
HTTP 公钥固定 0 HTTP 公钥固定(HPKP)标头未实现(可选)
HTTP 严格传输安全 0 HTTP 严格传输安全 (HSTS) 标头设置为至少六个月 (15768000)
重定向 0 初始重定向到同一主机上的 https,最终目的地是 https
推荐人政策 0 Referrer-Policy 标头未实现(可选)
子资源完整性 0 子资源完整性 (SRI) 未实现,但所有脚本均从相似的来源加载
X-Content-Type-选项 0 X-Content-Type-Options 标头设置为"nosniff"
X-Frame-选项 +5 通过 CSPframe-ancestors指令实现的 X-Frame-Options (XFO)
X-XSS 保护 0 X-XSS-Protection 标头设置为"1; mode=block"

我们达到了 A+ 的评分!对于一个小时的工作来说,这已经很不错了,而且用户现在访问我们的网站时也更加安全了。

额外积分

我们现在进入最后冲刺阶段。我们可以采取一些可选措施来进一步增强安全性和隐私性。

推荐人政策

浏览器包含一个Referrer标头,用于识别用户访问新页面时来自哪里。它有助于追踪用户来自哪里,但也存在一些隐私问题。Referrer-Policy标头控制何时​​提供信息以及提供多少信息。

  • no-referrer。告诉浏览器永远不要发送Referer标头。
  • same-origin. 发送引荐来源网址,但仅限于网站内部的请求(例如 /security-in-the-static-buildpack => /posts)
  • strict-origin. 将引荐来源信息发送到所有来源,但仅发送不带路径的 URL(例如https://example.com/
  • strict-origin-when-cross-origin. 发送同源的完整引用信息,但仅发送外部来源的无路径 URL。

no-referrer可以用作浏览器的后备,因为其中许多选项目前尚未实现。

Referrer-Policy: no-referrer, strict-origin-when-cross-origin
Enter fullscreen mode Exit fullscreen mode

更多的?

Mozilla Observatory 还对Cookies子资源完整性进行了测试,但是在我们进行更改之后,它对 Keep Ruby Weird 网站感到满意,因此这些留给读者作为练习。

最终结果

这是此更改的最终结果,排除了对 HSTS 的选择加入“预加载”指令,这是我们对所有静态构建包应用程序的建议。

{
  "headers": {
    "/**": {
      "Content-Security-Policy": "default-src 'self'; script-src https://static.ads-twitter.com https://www.google-analytics.com 'sha256-q2sY7jlDS4SrxBg6oq/NBYk9XVSwDsterXWpH99SAn0='; img-src 'self' https://s3.amazonaws.com https://twitter.com https://pbs.twimg.com; font-src 'self' https://fonts.gstatic.com; style-src 'self' https://fonts.googleapis.com; frame-ancestors 'none';",
      "Referrer-Policy": "no-referrer, strict-origin-when-cross-origin",
      "Strict-Transport-Security": "max-age=63072000; includeSubDomains",
      "X-Content-Type-Options": "nosniff",
      "X-Frame-Options": "DENY",
      "X-XSS-Protection": "1; mode=block"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/heroku/using-http-headers-to-secure-your-site-2no0
PREV
大 O 符号基础变得非常简单关于大 O 的简短对话
NEXT
Postgres 被低估了——它处理的能力超出了你的想象