如何在Node.js中使用SSL / TLS
本文转载自微信公众号「新钛云服 」,作者魏建民 翻译 。转载本文请联系新钛云服公众号。
在2020年,您的网站没有理由不使用HTTPS。访客期望它,Google将其用作排名因素,浏览器制造商很乐意于点名那些没有使用它的网站。在本教程中,我将引导您通过一个实际示例,
说明如何将Let's Encrypt生成的证书添加到Express.js服务器。但是,仅使用HTTPS保护我们的网站和应用程序还不够。我们还应该要求正在与之通信的服务器进行加密连接。我们将看到有可能激活SSL / TLS层,即使默认情况下未启用它也是如此。
注意:如果您在配置NGINX作为Node应用程序的反向代理时正在寻找有关如何使用NGINX设置SSL的说明,请查看我们的快速提示“ 使用Node.js配置NGINX和SSL ”。
让我们从简短回顾一下HTTPS的当前状态开始。
一、HTTPS无处不在
HTTP / 2规范于2015年5月以RFC 7540的形式发布,这意味着它是该标准的一部分。这是一个重要的里程碑。现在,我们都可以将服务器升级为使用HTTP / 2。最重要的方面之一是与HTTP 1.1的向后兼容性以及选择不同协议的协商机制。尽管该标准未指定强制加密,但是当前没有浏览器支持未加密的HTTP / 2。这给HTTPS带来了另一个提升。终于,HTTPS无处不在!
我们的堆栈实际上是什么样的?从浏览器中运行的网站(在应用程序级别)的角度来看,我们必须遍历以下几层才能达到IP级别:
1.客户端浏览器、
2.HTTP、
3.SSL / TLS、
4.TCP协议、
5.知识产权
HTTPS就是SSL / TLS之上的HTTP协议。因此,所有HTTP规则仍然适用。这个额外的层实际上给了我们什么?有很多优点:我们通过拥有密钥和证书来进行身份验证;由于以非对称方式对连接进行加密,因此可以确保某种类型的隐私和机密性;并且还保留了数据完整性,因为传输的数据在传输过程中无法更改。
最普遍的神话之一是,使用SSL / TLS的计算量很大,并且会降低服务器的速度。这肯定不再是事实。我们也不需要带有加密单元的任何专用硬件。即使对于Google而言,SSL / TLS层也占不到CPU负载的1%,与HTTP相比,HTTPS的网络开销也低于2%。总而言之,为了节省一些开销,放弃HTTPS是没有意义的。
最新版本是TLS 1.3。TLS是SSL的后继产品,最新版本的SSL 3.0中提供了TLS。从SSL到TLS的更改排除了互操作性,但是基本过程保持不变。我们有三个不同的加密通道。第一个是用于证书链的公钥基础结构。第二种提供用于密钥交换的公共密钥加密。最后,第三个是对称的。在这里,我们有用于数据传输的密码学。
TLS 1.3对某些重要操作使用哈希处理。从理论上讲,可以使用任何哈希算法,但是强烈建议使用SHA2或更强大的算法。SHA1长期以来一直是标准,但最近已过时。
HTTPS也越来越受到客户的关注。隐私和安全问题一直存在,但是随着在线可访问数据和服务数量的增长,人们越来越关注。对于那些未实现此功能的网站,有一个有用的浏览器扩展-EFF的HTTPS Everywhere-可加密我们与大多数网站的通信。
创建者意识到许多网站仅部分提供HTTPS。该插件使我们可以重写仅提供部分HTTPS支持的网站的请求。另外,我们也可以完全阻止HTTP(请参见上面的屏幕截图)。
二、基本说明
证书的验证过程包括验证证书签名和有效期。我们还需要验证它是否链接到受信任的根。最后,我们需要检查它是否已被撤销。世界上有专门的可信赖的机构来颁发证书。如果其中之一遭到破坏,则来自该机构的所有其他证书将被吊销。
HTTPS握手的序列图如下所示。我们从客户端初始化开始,然后是带有证书和密钥交换的消息。服务器发送完成的包后,客户端可以开始密钥交换和密码规范传输。至此,客户端结束。最后,服务器确认密码规范选择并关闭握手。
整个序列独立于HTTP触发。如果我们决定使用HTTPS,则仅更改套接字处理。客户端仍在发出HTTP请求,但是套接字将执行前面描述的握手并加密内容(标头和正文)。那么,要使SSL / TLS与Express.js服务器一起使用,我们需要做什么?
三、HTTPS
默认情况下,Node.js通过HTTP提供内容。但是,还必须使用HTTPS模块,以便通过安全通道与客户端进行通信。这是一个内置模块,用法与我们使用HTTP模块的方式非常相似:
暂时忽略/srv/www/keys/my-site-key.pem和和/srv/www/keys/chain.pem文件。这些是我们需要生成的SSL证书,我们稍后会做。这是让我们加密的部分。以前,我们必须生成一个私钥/公钥对,将其发送给受信任的机构,向他们付款并可能要花一点时间才能获得SSL证书。如今,“让我们加密”可立即免费生成并验证您的证书!
四、生成证书
(1)Certbot
TLS规范要求证书,该证书由受信任的证书颁发机构(CA)签名。CA确保证书持有人确实是他们声称的真实身份。因此,基本上,当您看到绿色的锁定图标(或浏览器中URL左侧的任何其他绿色符号)时,表明您与之通信的服务器确实是它声称的身份。如果您在facebook.com上并且看到一个绿色锁,则几乎可以确定您确实在与Facebook通信,并且没有人可以看到您的通信,或者,也没有其他人可以阅读它。
值得注意的是,此证书不一定必须由诸如“加密”之类的权威机构进行验证。还有其他付费服务。您可以从技术上亲自对其进行签名,但是(由于您不是受信任的CA),访问您网站的用户可能会看到大量可怕的警告信息,以使他们恢复安全。
在下面的示例中,我们将使用Certbot,它用于通过Let's Encrypt生成和管理证书。在Certbot网站上,您可以找到有关如何为几乎所有OS /服务器组合安装Certbot的说明。您应该选择适合您的选项。
在最新的LTS Ubuntu上,NGINX是部署Node应用程序的常见组合,这就是我将在这里使用的。
(2)Webroot
Webroot是一个Certbot插件,除了Certbot默认功能(该功能会自动生成您的公钥/私钥对并为其生成SSL证书)外,还将证书复制到您的webroot文件夹中,并通过放置一些验证码来验证服务器进入名为的隐藏临时目录.well-known。为了跳过手动执行的某些步骤,我们将使用此插件。该插件默认情况下与Certbot一起安装。为了生成和验证我们的证书,我们将运行以下命令:certbot certonly --webroot -w /var/www/example/ -d www.example.com -d example.com
您可能必须以sudo身份运行此命令,因为它将尝试写入/var/log/letsencrypt。
您还会被要求提供您的电子邮件地址。最好输入一个经常使用的真实地址,因为如果证书即将过期,您会收到通知。让我们加密发行免费证书的权衡是该证书每三个月到期一次。幸运的是,更新就像运行一个简单的命令一样容易,我们可以将其分配给cron作业,而不必担心过期。此外,更新SSL证书是一种很好的安全做法,因为它可使攻击者更少的时间来破坏加密。有时,开发人员甚至将这个cron设置为每天运行,这是完全可以的,甚至建议这样做。
请记住,您必须在-d(针对域)标志下指定的域解析为的服务器(即生产服务器)上运行此命令。即使您的本地主机文件中有DNS解析,该方法也无法使用,因为该域将从外部进行验证。因此,如果您在本地执行此操作,则很可能会失败,除非您打开了从本地计算机到外界的端口,并使该端口在解析为您的计算机的域名后面运行。这是极不可能的情况。
最后但并非最不重要的一点是,在运行此命令之后,输出将包含私钥和证书文件的路径。将这些值复制到上一个代码段中- cert证书的key属性和密钥的属性中:
五、思考
(1)HTTP严格传输安全
您是否曾经在一个网站上从HTTP切换到HTTPS,并且仍有一些剩余重定向仍在重定向到HTTP?HTTP严格传输安全性(HSTS)是一种Web安全策略机制,可缓解协议降级攻击和cookie劫持。
HSTS有效地迫使客户端(浏览器访问您的服务器)通过HTTPS引导所有流量,这是“安全或根本不安全”的思想!
Express JS默认情况下不允许我们添加此标头,因此我们将使用Helmet,这是一个允许我们执行此操作的Node模块。通过运行以下命令安装头盔:npm install helmet然后,我们只需将其作为中间件添加到Express服务器中即可:
(2)Diffie-Hellman Strong(er)参数
为了跳过一些复杂的数学运算,让我们开始追逐。用非常简单的术语来说,有两种不同的密钥用于加密:从证书颁发机构获得的证书,以及由服务器生成的用于密钥交换的证书。密钥交换的默认密钥(也称为Diffie-Hellman密钥交换,即DH)使用的“密钥”比证书的密钥“小”。为了解决这个问题,我们将生成一个强大的DH密钥,并将其提供给我们的安全服务器以供使用。
为了生成更长的密钥(2048位),您将需要openssl默认安装的。如果您不确定,请运行openssl -v。如果找不到该命令,请openssl通过运行安装sudo apt install openssl(或在此处访问其下载页面):openssl dhparam -out /var/www/example/sslcert/dh-strong.pem 2048
然后将文件的路径复制到我们的配置中: