第二章:TLS连接

在互联网的早期,我们很乐意通过网络获取数据。我们没有资源对其进行加密,也没有愚蠢到认为任何人都应该信任网络中的重要数据。然后我们让你们其他人上网(出于某种原因,我仍然无法理解),传输加密变得至关重要。SSL是TLS的前身,它以当时最合理的方式嵌入到现有的网络服务中。 TLS继承了这些方法,你必须能够应对它们。

调试网络守护进程的一个关键工具是消除用户友好的客户端,并使用 netcat(1) 等工具以交互方式连接到守护进程。如果我想知道SSH或SMTP守护进程是否可访问,我可能会使用netcat连接到端口22或25。我能拿回协议横幅吗?或者有什么东西接受连接但不回答?

我在和邮件服务器说话。网络工作。如果我熟悉现代SMTP协议,我甚至可以与服务器聊天。您可以对任何基于文本的协议执行相同的操作。

TLS使此调试复杂化。如果我使用netcat连接到TLS包装的端口,我将在纯文本客户端中获得二进制TLS。这不会让我高兴的。我需要我的客户端为我处理TLS。OpenSSL包含 s_client 子命令,用于创建和调试TLS包裹的网络连接。我们将演示如何使用 s_client 连接到守护进程,以便您可以手动查询自己的守护进程。

许多netcat变体支持TLS,甚至具有TLS调试功能。然而,每个netcat分支都选择了不同的功能和独特的参数,所以我不能在这里记录它们。因此,这些示例都使用 s_client 来建立您的理解。一旦你知道TLS连接是如何工作的,以及“正常”是什么样子,就可以使用你喜欢的任何工具。

第二章:TLS连接连接到端口连接与调试回车与换行TLS专用TCP端口机会主义TLS连接命令DTLS静音 s_client特定 TLS版本选择密码

连接到端口

客户端通过直接TLS连接、具有CR/LF处理的TLS连接、STARTTLS或DTLS等方法连接到网络端口。

连接与调试

编写 s_client 命令是为了调试TLS连接。当它发现无效证书时,默认情况下会接受它们并继续。如果您依赖OpenSSL来暴露TLS问题,请在所有 s_client 命令中添加 -verify_return_error 标志。如果您正在调查TLS包装中的守护进程或应用程序协议问题,则可以跳过此标志。

s_client 命令包括各种特定的调试选项,以及用于异常边缘情况和真正奇怪情况的标志。如果你有一个问题,看起来不仅奇怪,而且完全反常,请阅读手册页,看看是否有任何合适的地方。

回车与换行

任何读过这本书的人都会被不同操作系统对待“转到下一行”字符的方式绊倒。Unix将换行符(line feed —— LF)视为新行。Microsoft操作系统将带有换行符的回车符(carriage return with a line feed —— CRLF)视为新行。早期的MacOS使用回车符(carriage return —— CR)作为换行符,谁知道其他操作系统使用什么?FTP的二进制和ASCII模式用于处理换行符。

这种差异扩展到纯文本网络协议。一些协议,如HTTP,希望能够在不获得新行的情况下发送回车符。OpenSSL需要同时应对这两种情况。

现代OpenSSL使用 -connect-crlf 选项连接到网络端口。 -connect 命令将 ENTER 视为带换行符的回车符,而 -crlf 则将 ENTER 视为回车符。

对于LibreSSL和较旧的OpenSSL,您必须始终使用 -connect 指定目标主机和端口。如果需要换行处理,请添加 -crlf

此外,一些Unix附带了行为不同的修改过的OpenSSL。如果 -connect-crlf 不起作用,请尝试另一个。

TLS专用TCP端口

web、电子邮件和FTP等常见网络服务连接到专用TCP/IP端口。用TLS封装守护进程连接的最简单方法是为受TLS保护的版本分配不同的端口。这就是为什么HTTP在TCP端口80上运行,而HTTPS使用端口443。应用程序开发人员必须对他们的应用程序进行相对较小的更改,并且不必太担心TLS的内部。

这里我的邮件客户端让我很恼火,我不确定是网络、我的客户端还是我,所以我使用 s_client 直接与专用于TLS包裹的POP3的TCP端口通信。 -connect 参数告诉 s_client 创建一个到给定主机和端口的TLS隧道。我添加 -verify_return_error 是因为如果它是TLS错误,我想知道它的相关信息。

我将在第5章中看到大量TLS信息。出现一条双点划线,声明 s_client 已完成工作,守护进程对连接做出响应。

我可以使用原始POP3协议来查看服务器是否正常工作。

结果将我的问题转化为:为什么我的邮件客户端没有报告此错误?

网络流量略有不同。我的网站都将流量从HTTP重定向到HTTPS,并将主机名的www版本重定向到裸域,即, http://www.mwl.io 重定向到 https://mwl.io 。这使得各种攻击成为可能,但我的网站既不保密也不重要。(我还启用了HSTS,如第8章所述。)重新配置服务器后,我想验证这些重定向是否仍在运行。浏览器会缓存各种碎屑,所以我不信任它们。相反,我想直接询问服务器。HTTP将CR和LF分开,所以我必须对 s_client 使用 -crlf 选项。

如果您运行的是较旧的OpenSSL或LibreTLS,请同时使用 -crlf-connect

我得到了所有的TLS信息,最后有一条双虚线。

Web服务器在连接时不提供协议横幅。我输入我的HTTP命令。

我在两行之间按了一次回车键。HTTP请求以两个ENTER结束,因此当我完成命令时,我按ENTER ENTER。它回应:

我的重定向是完整的。

s_client 命令从您连接到的主机名中获取SNI服务器名。如果必须指定其他SNI服务器名称,请使用 -servername 选项。在这里,我想确保我在新服务器上安装的网站能够正常工作,即使它是在临时主机名上:

为服务的TLS版本使用单独的端口号是可行的,但虽然网络端口很多,但它们并不是无限的。此外,该技术增加了网络流量并减慢了服务速度。我们需要更好的。

机会主义TLS

在某些协议中,客户端可以请求服务器使用TLS,服务器可以请求客户端升级到TLS。这个想法是在TLS可用时使用它,但如果TLS不可用,则允许继续使用。这种机会性TLS(opportunistic TLS)非常适合电子邮件等通用协议,在这些协议中,每个人都有一台服务器,他们不能同时升级。人们的期望是,最终所有应用程序都将支持TLS。机会性TLS通常在电子邮件的协议内命令请求TLS后被称为 STARTTLS ,但并非所有机会性的TLS实现都使用字面命令STARTTLS。

“机会主义”听起来很灵活,但使用机会主义TLS的服务器可能会僵化地要求TLS。当客户端连接时,服务器可能会请求TLS。如果客户端拒绝,服务器可以声明“Sorry, TLS or nothing”并断开连接。

每个协议看起来都不同,因此每个协议都必须以不同的方式实现机会TLS。它们是相似的,但用于电子邮件的SMTP协议与LDAP、XMPP或其他任何协议都不相似。在尝试将服务器的机会性TLS与 s_client 一起使用之前,请检查手册页中的 -starttls 选项,查看您的实现是否支持该协议。注意 s_client 用于协议的名称。

我们将以电子邮件为例。电子邮件和TLS的历史因电子邮件的演变、桌面邮件客户端、基于网络的电子邮件的快速发展以及几十年来的变通方法和从信鸽、UUCP等更糟糕的迁移路径而变得复杂。电子邮件自私地霸占TCP端口25、465和587,并表示不愿意放弃其中任何一个。在这里,我使用 s_client 通过STARTTLS连接到端口25上的邮件服务器:

我们使用熟悉的openssls_client命令,以及带有主机和端口的相同 -connect 关键字。新位在末尾。 -starttls 选项告诉 s_client 立即协商TLS会话。然后,我们给出协议名称,在本例中为 smtp

你会得到通常的TLS信息,然后是:

我现在可以进行我通常的SMTP手动恶作剧了:

我的RBL订阅有效吗?很好。不幸的是,我正在测试我的家庭地址被RBL覆盖了。

虽然桌面邮件应用程序非常关心服务器证书的有效性,但邮件服务器之间的TLS连接完全满足于自签名证书。在服务器到服务器的邮件中,没有人参与决定是否应该覆盖警告,电子邮件特别不关心发送主机的身份。没关系。服务器到服务器SMTP的存在主要是为了防止美国政府的食肉动物(Carnivore)等系统大规模捕获电子邮件。SMTP的TLS接受服务器上的自签名和过期证书,因为自签名证书足以防止网络上的被动窥探。攻击者仍然可以进行人中攻击,这在规模上更具挑战性。

隐私敌对网络,包括某些国家的整个互联网,通常会阻止STARTTLS。但是,它们也会阻止专用TLS端口。

连接命令

s_client 会话将保持打开状态,直到您终止它。虽然 CTRL-C 是历史悠久的断开连接的方法,但您确实有其他选择。

输入 Q 会干净地关闭TLS连接。

最棘手的是更改实时TLS会话的命令。输入 k 会发送TLS 1.3密钥更新,而 k 既发送更新又请求更新。如果此连接使用较旧的TLS版本,它将断开连接。输入 R 会重新协商TLS 1.2会话。

大多数人不需要这些,但它们的存在本身就可能造成问题。如果你使用的协议有以这些字母开头的命令怎么办?我不知道有哪种协议的命令以 Q 开头,但每次你尝试用 s_client 调试它时,OpenSSL都会挂断。

-ign_eof 标志旨在确保TLS连接在任何输入结束后仍保持活动状态。它具有禁用这些命令的副作用。

如果你使用 s_clients_server 在网络netcat风格中抛出文件,那么 -ign_eof 标志几乎是强制性的。

DTLS

手动测试DTLS类似于在netcat中使用其他基于UDP的协议。它需要对底层协议有广泛的了解。这不是你随便做的事。SCTP积极反对这种交互式使用。如果你有兴趣在UDP或SCTP上使用TLS,许多人已经为他们编写了简单的响应程序。

还可以看看OpenSSL的 s_server 子命令,它允许您创建等效于DTLS中封装的netcat侦听器。大多数netcat变体都有类似的功能。

静音 s_client

也许你知道TLS正在工作,你只是想戳一下下面的守护进程。所有这些低级TLS信息都只是分散注意力。添加 -quiet 标志以使除证书链摘要之外的所有内容静音。

要查看协商的TLS特性的摘要,请使用 -lief

我现在可以输入我的HTTP命令,并被告知此网站已移动,而无需费力地浏览所有TLS细节。

特定 TLS版本

当像 s_client 这样的TLS客户端首次连接到服务器时,客户端会列出它支持的TLS版本。服务器选择它支持的最高版本。为了调试,您可能需要强制使用特定的TLS版本,或者禁止此连接使用某些TLS版本。OpenSSL为两者都提供了命令行选项。 -tls1_3 标志意味着只接受TLS 1.3,而 -tls1_2 强制TLS 1.2。如果你正在检查TLS的过时版本,还有 -tls1_1-tls1-ssl3

假设我将web服务器配置为只接受TLS 1.2和1.3。Web服务器很复杂。我完全有可能错过了什么。我必须核实我的工作。

如果所有这些返回错误,则连接不成功。这些TLS版本在我的服务器上不起作用。然而,我可能应该验证TLS 1.2和1.3是否也能正常工作:

这些标志也出现在禁止特定协议的“否”版本上。通过添加 -no_ssl3-no-tls1-no-tlls1_1-no_tls1_2-no-tls1_3 ,可以分别禁止 s_client 使用SSLv3或TLS 1、1.1、1.2和1.3。检查网站是否支持1.2和1.3以外的TLS版本可以在单个命令中运行,如下所示:

如果此服务器支持1.3和1.2以外的任何TLS版本, s_client 将找到它。

不要混合使用 -tls-no-tls 标志。要么声明协议版本,要么禁止协议版本。

s_client 子命令还有许多其他选项。使用 -help 参数获取完整列表,或阅读手册页。

选择密码

也许你想模拟一个特定的客户端,或者想测试服务器上是否有某些密码可用。如果您检查web浏览器的TLS连接详细信息或客户端程序的日志,您将看到密码名称和TLS版本。该密码名称可能是密码的OpenSSL名称、IANA名称、GnuTLS名称或其他名称。使用https://ciphersuite.info查找OpenSSL密码名称,以便您可以在 s_client 命令中指定该密码。 -cipher 选项允许您指定TLS 1.2选项,而 -ciphersuite 允许您指定TLS1.3密码。

但是,为特定TLS版本设置密码列表并不意味着 s_client 会自动使用该TLS版本。也许吧。可能不会。如果您正在测试特定的密码,请同时指定TLS版本。

现在让我们考虑一下证书本身。