混合内容 & https 升级攻略

4,843 阅读9分钟

又是一篇由 Chrome 升级 80 引发的文章。

(上一篇文章是由 Chrome 80 对跨站 Cookie 的 SameSite 默认值进行改变引发的: 《当 CORS 遇到 SameSite》

最近发现有的后台系统遇到了加载视频资源失败的问题,明明之前都是好使的呀!打开控制台看下报错:

GET https://video.example.com/id net::ERR_CERT_COMMON_NAME_INVALID

诶,奇怪。我要加载的资源明明是 http 的,为什么会发出 https 的请求呢?

进一步探索,发现是因为 Chrome 升级 80 对混合内容资源加载策略进行了改变。

接下来详细介绍一下所谓混合内容以及浏览器针对的行为,最后介绍 HTTPS 升级攻略。

接下来文章分几个部分:

  1. 什么是混合内容?
  2. 混合内容的危害
  3. Chrome 针对混合内容的升级行为
  4. 升级 HTTPS 攻略
  5. 升级 HTTPS 带来的好处以及你可能会有的疑虑

混合内容

什么是混合内容?

混合内容(mixed content)是指:HTTPS 页面包含 HTTP 子资源

Note: 在 HTTP 页面中包含 HTTPS 资源完全没问题。

混合内容的分类

  1. 被动混合内容
    • 指不与页面其余部分进行交互的内容。被动混合内容包括 图像、视频和音频内容,以及无法与页面其余部分进行交互的其他资源
    • 因为被动混合内容不与页面其他部分进行交互,从而也限制了中间人攻击再拦截或更改该内容时能够执行的操作
    • 也正因此,被动混合内容的危害相比主动混合内容稍小一些,在第三节我们会看到,浏览器对被动混合内容的资源也会更“宽容” 。
  2. 主动混合内容
    • 作为整体与页面进行交互,并且几乎允许攻击者对页面进行任何操作。
    • 主动混合内容包括浏览器可下载和执行的 脚本、样式表、iframe、flash 资源及其他代码

<a> 标签

<a> 标签不会产生混合内容,因为 <a> 标签的作用是使浏览器导航到新页面。

但是有些图像库脚本替换了 <a> 标签的功能,并将 href 属性指定 HTTP 资源加载到页面,从而引发混合内容问题。 比如下面的代码:

<a class="gallery" href="http://googlesamples.github.io/web-fundamentals/fundamentals/security/prevent-mixed-content/puppy.jpg">
   <img src="https://googlesamples.github.io/web-fundamentals/fundamentals/security/prevent-mixed-content/puppy-thumb.jpg">
</a>

<a> href 设置为http://看上去可能是安全的;但是,如果查看示例并点击图像,将会发现其加载一个混合内容资源并在页面上显示。

混合内容的风险

混合内容的危害简单来说就是 明文传输 带来的风险,举几个例子:

  1. 篡改风险:攻击者可以篡改股票图表的混合 image 来误导消费者;或将追踪 cookie 注入混合资源中
  2. 窃听风险:窃听者可以获取图片内容,设置用户 cookie 等;
  3. 导致浏览器安全性 UX 混乱

Chrome 针对混合内容的升级行为

  1. 在 Chrome 79 之前: 浏览器默认情况会阻止多种类型的混合内容,如 scriptiframe,但是 imagesaudiovideo 仍然可以加载
  2. Chrome 79 中可以通过设置取消阻止特定网站上的混合内容(scriptsiframe 和 Chrome 当前默认阻止的其他类型的内容)。 可以点击 https 页面上的锁定图标来切换此设置

3. Chrome 80混合的 audiovideo 资源将会自动升级到 https://, 并且默认情况下,如果它们无法通过 https:// 加载,Chrome 将阻止它们;Chrome 80 中仍然可以加载混合图像,但是它们会使 Chrome 在多功能框中显示 Not Secure
4. Chrome 81 中,混合 image 会自动升级到 https:// 。如果无法通过 https:// 加载,Chrome 默认会阻止它们

HTTPS 升级攻略

上面介绍了 HTTPS 页面加载 HTTP 混合内容引发的问题;上一篇文章介绍了 HTTP 页面发起跨站请求时无法携带 cookie 的问题。看来升级 HTTPS 真的 是大势所趋!

下面就介绍一下网站升级 HTTPS 的攻略~

Step 1:证书申请与设置

第一步当然是申请与设置证书了!

主要有下面四个步骤:

  1. 创建一个 2048 位 RSA 公钥/私钥对。
    • 为什么选择2048呢? 较短的密钥,如 1024 位,不足以抵御暴力猜测攻击。 较长的密钥,如 4096 位,则有点过度。 长远来看,随着计算机处理开销降低,密钥长度会增加。 目前 2048 是最佳长度。
      openssl genrsa -out www.example.com.key 2048
      
  2. 生成一个嵌入公钥的证书签名请求 (CSR)
    • 将公钥和有关组织及网站的信息嵌入到证书签名请求(或 CSR)中
  3. 将 CSR 与证书颁发机构 (CA) 共享以接收最终证书或证书链。
    • 可以选择将密钥映射到多个 DNS 名称,包括多个独立名称(例如 example.com、www.example.com、example.net 和 www.example.net 的全部)或“通配符”名称(*.example.com)
    • 通配符证书一般比标准证书更贵。因此当有超过 n(n = 通配符证书价钱/标准证书价钱) 个以上子域名时,通配符证书比较划算
  4. 将最终证书安装在非网络可访问的位置,例如 /etc/ssl(Linux 和 Unix)或 IIS 需要它的位置 (Windows)。

Step 2: 在服务器上启用 HTTPS

第一步和第二步的详细说明请参见这篇文章

Step 3:查找和修正混合内容

首先,如果是新的项目的话,建议直接使用相对路径或相对协议(省去协议)来链接资源地址。例如://example.com/something.js

如果是老项目升级的话,因为项目里也许已经有很多资源写死了协议,则可以采用下面两种办法:

  1. 手动查找与修正
  • 在控制台中看有没有错误/警告 或者 在源码中搜索 http://
  • 修正:
    • 如果资源已经支持 HTTPS(在浏览器中直接用 https 协议打开可以正常访问),则可以直接更换资源地址或改成相对协议
    • 如果资源不支持 HTTPS,联系图片服务提供商等进行升级
  1. 使用内容安全策略(CSP)自动收集与修正

    可以通过在服务器发送的响应中添加 Content-Security-PolicyContent-Security-Policy-Report-Only 标头为页面启用这些功能。此外,在页面的 <head> 部分中,可以使用一个 <meta>标记设置 Content-Security-Policy(不适用于 Content-Security-Policy-Report-Only

    相关 header:

    1. 收集不安全的资源: Content-Security-Policy-Report-Only

      例:

      Content-Security-Policy-Report-Only: default-src https: 'unsafe-inline' 'unsafe-eval'; report-uri https://example.com/reportingEndpoint
      

      表示收集(但不强制执行)违背内容安全策略的 JSON 格式报告(向 https://example.com/reportingEndpoint 发送)

    2. 升级不安全的请求: upgrade-insecure-requests CSP 指令

      指示用户代理将站点的所有非导航不安全 URL (HTTP) 自动升级(第一方 和第三方请求)。如果资源不能通过 HTTPS 获得,则升级的请求失败,并且无法加载该资源。

      非导航不升级的意思是: 比如 <a> 标签不会升级 <a href="http://not-example.com/">Home</a> 是 ok 的

      设置方法1:

      Content-Security-Policy: upgrade-insecure-requests
      

      设置方法2:

      <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
      
    3. 阻止所有混合内容: Content-Security-Policy CSP 指令

      当页面使用 HTTPS 加载时,阻止加载所有 HTTP 资源

      方法1:

      Content-Security-Policy: block-all-mixed-content;
      

      方法2:

      <meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">
      

      如果要详细禁止使用的 HTTP 资源,可以将单个指令设置为 https。比如要禁止不安全的 http 图片:

      Content-Security-Policy: img-src https:
      
    4. Upgrade-Insecure-Requests:1

      GET / HTTP/1.1 
      Host: example.com 
      Upgrade-Insecure-Requests: 1
      

      客户端向服务端请求时发送信号,表明它支持 upgrade-insecure-requests 的升级机制,服务端可重定向到站点的安全版本。

      可以使用 Vary 标头,以便缓存不会将站点提供给不支持升级机制的客户端

      Location: https://example.com/ 
      Vary: Upgrade-Insecure-Requests
      

Step4: 将 HTTP 重定向到 HTTPS

<link rel="canonical" href="https://…"/>

整合重复网址方法参见这里

Step5: 打开严格传输安全和安全 Cookie

  1. 使用 HTTP 严格传输安全 (HSTS) 来避免 301 重定向产生的开销。

    • 告诉客户端始终应通过 HTTPS 来连接您的服务器,即使在访问 http:// 时也是如此
    • 这样可以避免 SSL 剥离 之类的攻击,还可以避免在将 HTTP 重定向到 HTTPS 时启用的 301 redirect 产生的往返开销

    Note: 如果您的网站在其传输层安全协议 (TLS) 配置中出现过错误(例如证书过期),则已将您的网站注明为已知 HSTS 主机的客户端可能出现硬故障。通过此方式显式设计 HSTS 可确保网络攻击者无法欺骗客户端访问没有 HTTPS 的网站。在确认您的网站运营足够可靠之前,不要启用 HSTS,以避免部署 HTTPS 时总是出现证书验证错误。

    • 通过设置 Strict-Transport-Security 标头来打开 HTTP 严格传输安全 (HSTS)
  2. 始终在 Cookie 上设置安全标记(Secure)

    • 确保客户端不会通过 HTTP 发送 Cookie(例如用于身份验证或网站偏好)(如果用户的身份验证 Cookie 将在明文中暴露,则其整个会话的安全保障将被破坏)
    1. 各个语言设置 Secure 方法见这里

升级 HTTPS 带来的好处以及你可能会有的疑虑

好处:安全

不必多说 (๑•̀ㅂ•́)و✧

其实这点就足够有力

好处:搜索排名

搜索引擎(如 Google)会将 HTTPS 作为肯定性的质量指标 (๑•̀ㅂ•́)و✧

疑虑:性能:HTTPS 是否会带来额外的性能问题?

  1. 当内容和应用层优化得当时(请参考 Steve Souders 的论著以获取很好的建议),相对于应用的总体开销而言,其余的传输层安全协议 (TLS) 性能问题一般都是小问题。此外,您可以减少和分摊那些开销。 (如需 TLS 优化建议和一般建议,请参考 IlyaGrigorik 撰写的高性能浏览器网络。) 另请参考 Ivan Ristic 的 OpenSSL 手册SSL 和 TLS 的防弹衣
  2. 在某些情况下,TLS 可以 提高性能,主要是可以采用 HTTP/2 所带来的结果。 Chris Palmer 在 Chrome 开发峰会 2014 上做过一个演讲,讨论 HTTPS 和 HTTP/2 的性能。

好处:导航来时可以引用更多的站点标头

当用户从 HTTPS 网站链接到其他 HTTP 网站时,User Agent 不会 引用站点标头

Caution: 根据 HTTP RFC(https://tools.ietf.org/html/rfc2616#section-15.1.3),如果引用页面是通过安全协议传输的,则客户端不能在(非安全)HTTP 请求中包括引用站点标头字段。

参考资料

No More Mixed Messages About HTTPS

W3C: Block all mixed content

防止混合内容

什么是混合内容?

在服务器上启用 HTTPS