稳定性:1 - 实验性
node:dtls 模块提供了在 UDP 之上实现的 Datagram Transport
Layer Security(DTLS)协议。DTLS 为基于数据报的通信提供与 TLS 等价的
安全保障,包括机密性、完整性和身份认证。
要使用此模块,必须在构建时通过 --experimental-dtls 配置标志启用,
并在运行时通过 --experimental-dtls CLI 标志启用。
node --experimental-dtls app.mjs使用 [权限模型][] 时,必须传入 --allow-net 标志以允许 DTLS 网络操作。
如果没有它,调用 dtls.connect() 或 dtls.listen() 将抛出
ERR_ACCESS_DENIED 错误。
node --permission --allow-fs-read=* --experimental-dtls index.mjs
Error: 对此 API 的访问已受限。请使用 --allow-net 来管理权限。
code: 'ERR_ACCESS_DENIED',
permission: 'Net',
}即使没有 --allow-net,也允许创建一个 DTLSEndpoint 实例而不进行连接或监听,
因为在调用 dtls.connect() 或 dtls.listen() 之前不会发生网络 I/O。
DTLS 专为 UDP 传输而设计,并在以下几个关键方面与 TLS 不同:
- 不保证流式传输:消息可能乱序到达或丢失。 DTLS 保留数据报语义。
- 一个套接字,多个对端:单个 UDP 套接字可服务多个 DTLS
会话。
DTLSEndpoint负责管理这种多路复用。 - Cookie 交换:DTLS 服务器使用无状态 cookie 机制 (HelloVerifyRequest)来防止拒绝服务放大攻击。
- 重传:由于 UDP 不保证送达,DTLS 会在内部处理握手重传。
创建一个绑定到指定地址和端口的 DTLS 服务器。该服务器 使用基于 HMAC 的自动 cookie 交换进行 DoS 防护。
import { listen } from 'node:dtls';
import { readFileSync } from 'node:fs';
const endpoint = listen((session) => {
session.onmessage = (data) => {
console.log('收到:', data.toString());
session.send('pong');
};
session.onhandshake = (protocol) => {
console.log('握手完成:', protocol);
};
}, {
cert: readFileSync('server-cert.pem'),
key: readFileSync('server-key.pem'),
port: 4433,
});
console.log('DTLS server listening on', endpoint.address);连接到 DTLS 服务器。返回一个 DTLSSession,其 opened 属性是一个
Promise,在握手完成时解析。
import { connect } from 'node:dtls';
import { readFileSync } from 'node:fs';
const session = connect('localhost', 4433, {
ca: [readFileSync('ca-cert.pem')],
});
await session.opened;
session.send('hello');
session.onmessage = (data) => {
console.log('收到:', data.toString());
};管理一个 UDP 套接字并对 DTLS 会话进行多路复用。
该端点绑定到的本地地址。
包含以下属性的共享状态对象:
为此端点收集的统计信息。只读。该统计对象是 实时的,并随着数据流经端点由 C++ 内部更新。
当为 true 时,端点会拒绝新的传入连接。可用于实现背压。
优雅地关闭端点。在释放 UDP 套接字之前,所有活动会话都会通过
close_notify 警报关闭。
端点收集到的统计信息视图。
如果统计对象仍连接到底层端点,则为 true。
一旦端点被销毁,统计信息就会变为过时快照。
表示与单个远程对端的 DTLS 关联。
向对端发送应用数据。数据在通过 UDP 发送之前会由 DTLS 加密。
只能在握手完成后调用(session.opened 已解析)。
通过发送 close_notify 警报来启动优雅的 DTLS 关闭。
为此会话收集的统计信息。只读。该统计对象是 实时的,并随着数据流经会话而更新。
从 DTLS 会话导出密钥材料,如 RFC 5705 所定义。 这通常与 DTLS-SRTP 一起使用,以为媒体流派生加密密钥。
会话收集到的统计信息视图。
如果统计对象仍连接到底层会话,则为 true。
一旦会话被销毁,统计信息就会变为过时快照。<Buffer>
设置后可接收来自对端的应用数据。<Error>
设置后可接收错误通知。<string>
设置后可接收握手完成通知。<string>
设置后可接收 TLS 密钥日志行(用于使用 Wireshark 调试)。
DTLS-SRTP 被 WebRTC 用于媒体加密。DTLS 握手会协商 SRTP 保护配置文件并提供密钥材料。
import { listen, connect } from 'node:dtls';
import { readFileSync } from 'node:fs';
// 带 SRTP 的服务器
const server = listen((session) => {
session.onhandshake = () => {
console.log('SRTP 配置文件:', session.srtpProfile);
const keys = session.exportKeyingMaterial(
60,
'EXTRACTOR-dtls_srtp',
);
console.log('SRTP 密钥材料:', keys);
};
}, {
cert: readFileSync('server-cert.pem'),
key: readFileSync('server-key.pem'),
port: 5004,
srtp: 'SRTP_AES128_CM_SHA1_80:SRTP_AEAD_AES_128_GCM',
});
// 带 SRTP 的客户端
const session = connect('localhost', 5004, {
rejectUnauthorized: false,
srtp: 'SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80',
});
await session.opened;
console.log('协商的 SRTP:', session.srtpProfile);
const keys = session.exportKeyingMaterial(60, 'EXTRACTOR-dtls_srtp');由于 libuv 当前不支持路径 MTU 发现,DTLS 模块使用保守的默认 MTU 1200 字节。这个值适用于几乎所有网络路径,但在本地网络中可能并非最优。
可以通过 mtu 选项配置 MTU:
// 用于你已知路径 MTU 的本地网络
const endpoint = listen(callback, {
// ...
mtu: 1400,
});允许的最小 MTU 为 256 字节。最大值为 65535。