【发布时间】:2017-02-20 19:14:06
【问题描述】:
查看SecureSocket 的文档时,我看到secure/connect/secureServer 方法中有一个参数称为supportedProtocols。
- 这是什么?
- 可能的值是多少?
- 顺序重要吗?
【问题讨论】:
查看SecureSocket 的文档时,我看到secure/connect/secureServer 方法中有一个参数称为supportedProtocols。
【问题讨论】:
这是什么?
客户端支持的安全通信协议列表
可能的值是什么?
协议和版本的名称以斜线分隔(例如"http/1.1")
顺序重要吗?
是的。优先级是按降序设置的
一些解释:
TLS 有一个名为ALPN 的扩展名(顾名思义)用于协商用于安全通信的应用层协议。
在ALPN 中,协议使用我上面指定的格式进行标识。
SecureSocket 实现了TLS,因此必须接收要在ALPN 阶段使用的协议列表参数。
除非您的服务器和客户端正在实施自定义通信协议,否则我建议您只使用"http/1.1"。
更多信息:
我可以在 Dart 源中找到传递给 SecureServer 的协议列表的唯一文档是 SecurityContext._protocolsToLengthEncoding (io/security_context.dart:190):
/// Encodes a set of supported protocols for ALPN/NPN usage.
///
/// The `protocols` list is expected to contain protocols in descending order
/// of preference.
///
/// See RFC 7301 (https://www.rfc-editor.org/rfc/rfc7301) for the encoding of
/// `List<String> protocols`:
/// opaque ProtocolName<1..2^8-1>;
///
/// struct {
/// ProtocolName protocol_name_list<2..2^16-1>
/// } ProtocolNameList;
///
/// The encoding of the opaque `ProtocolName<lower..upper>` vector is
/// described in RFC 2246: 4.3 Vectors.
///
/// Note: Even though this encoding scheme would allow a total
/// `ProtocolNameList` length of 65535, this limit cannot be reached. Testing
/// showed that more than ~ 2^14 bytes will fail to negotiate a protocol.
/// We will be conservative and support only messages up to (1<<13)-1 bytes.
通过RFC 7301(ALPN 描述):
"ProtocolNameList" contains the list of protocols advertised by the
client, in descending order of preference. Protocols are named by
IANA-registered, opaque, non-empty byte strings, as described further
in Section 6 ("IANA Considerations") of this document.
还有section 6:
Protocol: HTTP/1.1
Identification Sequence:
0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1")
Reference: [RFC7230]
Protocol: SPDY/1
Identification Sequence:
0x73 0x70 0x64 0x79 0x2f 0x31 ("spdy/1")
Reference:
http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft1
Protocol: SPDY/2
Identification Sequence:
0x73 0x70 0x64 0x79 0x2f 0x32 ("spdy/2")
Reference:
http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
“标识序列”是 ASCII 字节中的协议标识符。是协商阶段通过socket发送的原始数据。
有趣的事实:在 Dart 中,SecurityContext._protocolsToLengthEncoding 方法将协议标识符从字符串编码为字节。
希望这有帮助!
【讨论】:
历史上未加密的应用程序协议通常分配有自己的端口(例如,80 用于http,25 用于smtp)。
ALPN:现在大多数流量都是通过 TLS 加密的,这是一种安全的传输协议。任何应用程序协议都可以使用它。除了为应用程序协议使用新的端口号之外,还可以使用不同的解决方案:TLS 支持称为 ALPN(应用程序级协议协商) 的扩展,它允许客户端/服务器告诉对等方他们支持哪些协议和他们喜欢什么(可能回退到由端口号推断的协议——这对向后兼容很有好处)
(旁注:还有一个称为 NPN“下一个协议协商”的前身 TLS 扩展,用于类似目的,但由于各种原因已被弃用)
最常见的用例是 http/2:服务器侦听端口 443 并提供说 http/1.1、http/2 和假设为 spdy。浏览器将与服务器端口443 建立 TCP 连接,让服务器知道它支持哪些协议。然后服务器将选择使用哪个协议(基于客户端发送的列表和服务器应用程序支持的内容)。为了向后兼容,如果未协商任何协议,客户端/浏览器将回退到 http/1.1。
协商与优先级有3种情况:
客户端或服务器不支持 ALPN 扩展:未协商任何协议
客户端和服务器支持 ALPN,但没有通用协议:没有新协议
客户端和服务器都支持 ALPN,并且有一个或多个协议都支持:优先级最高的协议。
Dart 支持:Dart 前段时间添加了对 ALPN 的支持,并通过可选的名为 supportedProtocols 的参数公开它
一旦建立了 TLS 连接,两端将能够通过SecureSocket.selectedProtocol 看到协商的协议。如果对端不支持 ALPN TLS 扩展或者没有通用协议,那么selectedProtocol 将是null。
supportedProtocols 中的协议以递减的方式指定(将选择列表中服务器/客户端通用的第一个)。
ALPN 标识符 协议标识符可以是什么并没有真正的限制。您的应用程序可以使用它自己的。虽然对于公共协议,通常 RFC 会推荐使用哪些标识符,例如 RFC 7540 在 section 3.1 中指定:
“字符串“h2”标识 HTTP/2 使用传输层安全 (TLS) 的协议”
自行检查:如果您非常好奇,可以使用网络数据包检查器(如 wireshark 的较新版本)检查 TLS 流量并查看提供的 ALPN 协议。
【讨论】: