Logo
Section 1 / 6

HTTP严格传输安全

在本节课中,我们将学习如何使用 HTTP 安全传输强制头(HTTP Strict Transport Security header)来确保通信安全,从而提升用户与网站之间的端到端通信安全性。

检查点

HTTP严格传输安全

在本节课中,我们将学习如何使用 HTTP 安全传输强制头(HTTP Strict Transport Security header)来确保通信安全,从而提升用户与网站之间的端到端通信安全性。

HTTP严格传输安全(HTTP Strict Transport Security,简称HSTS)是一种协议标准,通过SSL/TLS在HTTP上强制实现与服务器的安全连接。HSTS由服务器配置并通过HTTP头 Strict-Transport-Security 发送给任何HTTP客户端。该头信息指定了浏览器在此期间应仅通过HTTPS安全连接进行通信的时间段。

提示

当在不安全的HTTP连接上传输Strict-Transport-Security头时,浏览器会忽略它,因为连接本身不安全。

设置该头后,浏览器会查询一个预加载服务(如Google的),以判断该网站是否已选择启用HSTS。

风险

在使用安全的HTTPS连接时,仍可能面临恶意用户发起的中间人攻击(Man-In-The-Middle, MITM)。此类攻击会将后续对服务器的请求降级为HTTP连接。一旦建立HTTP连接,攻击者即可查看并读取所有经过的数据流。

有趣事实:
HSTS的原始草案于2011年由PayPal的Jeff Hodges、卡内基梅隆大学的Collin Jackson以及谷歌的Adam Barth发布。

即使网站使用HTTPS,仍可能发出不安全的HTTP请求。普通用户可能不会察觉异常,但仍可能暴露于中间人攻击中。

在下图(图1-1)所示的流程中,我们可以看到一个典型场景:服务器向浏览器返回登录页面的HTML文件,其中包含一些通过HTTP访问的资源(如http://cdn.server.com/images/submit.png),例如提交按钮的图片。

如果攻击者能够实施中间人攻击并“监听网络流量”,他们就能读取所有未加密的通信内容,包括携带敏感数据的HTTP请求。更严重的情况是,攻击者可以监视实际数据发送的位置,并访问为POST或PUT端点设置的HTTP资源。

...
图1-1 - 可视化HTTPS中间人攻击

解决方案

当Web服务器希望使用安全的HTTPS连接保护其客户端时,需要发送带有指定值的Strict-Transport-Security头,该值表示客户端应持续使用HTTPS连接发送请求的时间长度(单位为秒)。该时间到期后,客户端不再强制使用HTTPS。

例如,要指示浏览器在未来一小时内将所有发往服务器的请求升级为HTTPS,可使用如下配置:

1Strict-Transport-Security: max-age=3600

Helmet实现

要使用Helmet的HSTS功能,需通过npm安装相关包,并将其作为Node.js项目的依赖项添加:

1npm install helmet --save

接下来,配置hsts中间件,指示客户端在未来一个月内仅向服务器主机名发送HTTPS请求:

1const helmet = require("helmet"); 2 3// 设置HTTPS请求的有效期为1个月,单位为毫秒 4const reqDuration = 2629746000; 5 6app.use( 7 helmet.hsts({ 8 maxAge: reqDuration, 9 }) 10);

在上述代码中,我们指示Express应用使用hsts中间件,并对所有请求响应中包含Strict-Transport-Security头。

注意:如果浏览器接收到多个HSTS头指令,它只会遵循并执行第一个接收到的策略。

通常,Web服务器会拥有子域名,用于获取资源或调用REST API。我们也希望对这些子域名同样启用HTTPS保护。为此,可在hsts选项对象中加入以下可选参数:

1includeSubDomains: true;

提示

若需让浏览器禁用Strict-Transport-Security策略,服务器可将该头的max-age设为0。这将使浏览器立即失效该策略,从而允许通过不安全的HTTP连接访问。

练习

以下练习展示了如何使用HTTP严格传输安全(HSTS)作为浏览器安全控制机制,确保仅从网站主域名加载启用HTTPS的资源。

项目整体文件结构如下:

  1. server.js 中的Express服务器
  2. views/home.handlebars 中的Handlebars模板,作为示例网站
  3. public目录中包含一张我们将使用的图片

源码

您也可以从官方GitHub仓库 这里 获取源码,但平台运行的代码略有修改。

1const http = require("http"); 2const https = require("https"); 3var fs = require("fs"); 4const express = require("express"); 5const helmet = require("helmet"); 6const morgan = require("morgan"); 7const expressHandlebars = require("express-handlebars"); 8const appRoutes = require("./routes/app.routes.js"); 9 10const HTTP_PORT_NUMBER = 80; 11 12const httpApp = express(); 13httpApp.engine("handlebars", expressHandlebars()); 14httpApp.set("view engine", "handlebars"); 15 16httpApp.use( 17 helmet.hsts({ 18 maxAge: 86400, 19 }) 20); 21 22var options = { 23 key: fs.readFileSync("localhost-key.pem"), 24 cert: fs.readFileSync("localhost.pem"), 25}; 26 27httpApp.use(morgan("dev")); 28httpApp.use("/", appRoutes); 29 30httpApp.use(express.static("public")); 31 32const httpServer = http.createServer(httpApp); 33httpServer.listen(HTTP_PORT_NUMBER, function () { 34 console.log(`服务器已启动,端口:${httpServer.address().port}`); 35}); 36 37https.createServer(options, httpApp).listen(443);

运行项目

点击下方的RUN按钮运行示例应用,将打开一个Google Chrome窗口。

  • 可通过 http://localhost:80 查看HTTP版本
  • 可通过 https://localhost:443 查看HTTPS版本

No configuration found for ID: 7a3e826625b8d54404a816a8ac6972b99be931c6675d8b74c8faafbdcf3e2b59

练习1

当Express应用启动后,请访问:https://localhost:443

接着打开开发者工具调试应用的网络请求。可通过按下 CTRL+SHIFT+I 或 F12 实现。打开开发者工具后刷新页面,点击“网络”标签页。你会看到网页中包含的所有资源列表。点击“localhost”条目,在弹出窗口中切换到“Headers”标签页。你能看到HSTS头吗?

你是否检查了浏览器开发者工具中的网络标签?发现了什么?

你应该注意到以下几点:

  • 对页面 https://localhost:443 的主请求返回了 Strict-Transport-Security 安全头。
  • 加载图片的请求(在home.handlebars文件第138行可见)http://localhost/harley-davidson-zGzXsJUBQfs-unsplash.jpg 被浏览器自动重定向至其HTTPS版本——这是因为HSTS会将所有请求升级为对应的HTTPS版本以确保安全加载。
  • 来自 http://http.rip/favicon.ico 的图标被阻止加载。

在Chrome中调试HSTS设置

在实验HSTS头时,你可能会在“localhost”页面上设置它。这可能适得其反,因为HTTP页面会被强制重定向到HTTPS。

检查Chrome的HSTS设置

若出现此类问题,可检查Chrome中HSTS的配置,并手动添加或移除域名。在Chrome地址栏输入 chrome://net-internals/#hsts 并根据需要进行更新。

界面应如图1-2所示:

图1-2:Chrome内部HSTS配置
图1-2:Chrome内部HSTS配置

清除缓存

有时,Chrome的HSTS内部配置中没有本地主机条目,但仍会发生强制HTTPS重定向。

为确保清除缓存,请按以下步骤操作:

  1. 访问本地主机域名 http://localhost
  2. 按下 CTRL+SHIFT+I 或 F12 打开开发者工具
  3. 找到地址栏上的刷新图标,右键点击,在弹出菜单中选择“清空缓存并强制重新加载”

现在,通过HTTP访问本地主机网站(如 http://localhost:80)应能正常工作,不会再发生HTTPS重定向。

Quiz

1 / 2

简介

X-Frame-Options