QDtlsClientVerifier 类
此类实现了服务器端 DTLS 协议的 cookie 生成和验证。 更多...
头文件 | #include <QDtlsClientVerifier> |
CMake | find_package(Qt6 REQUIRED COMPONENTS Network) target_link_libraries(mytarget PRIVATE Qt6::Network) |
qmake | QT += network |
继承 | QObject |
- 全部成员列表,包括继承的成员
- QDtlsClientVerifier 是网络编程 API 的一部分。Network Programming API.
公共类型
公共函数
QDtlsClientVerifier(QObject *parent = nullptr) | |
虚拟 | ~QDtlsClientVerifier() |
QDtlsClientVerifier::GeneratorParameters | cookieGeneratorParameters() const |
QDtlsError | dtlsError() const |
QString | dtlsErrorString() const |
bool | setCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters ¶ms) |
QByteArray | verifiedHello() const |
bool | verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port) |
详细描述
QDtlsClientVerifier 类实现了服务器端 DTLS 协议的 cookie 生成和验证。数据报安全协议非常容易受到各种拒绝服务攻击。根据 RFC 6347,第 4.2.1 节,这些攻击中较为常见的是两种
- 攻击者发送一系列握手开始的请求,这将导致服务器分配过多的资源,并可能执行昂贵的加密操作。
- 攻击者发送一系列握手开始的请求,并伪造受害者的源头,令服务器充当放大器。通常,服务器会向受害者计算机发送证书消息,这可以相当大,从而将数据报洪泛至受害者计算机。
作为一种对这些攻击的应对措施,RFC 6347,第 4.2.1 节 提出了服务器可以部署的无状态 cookie 技术方法
- 针对最初的 ClientHello 消息,服务器发送包含 cookie 的 HelloVerifyRequest。
- 可到达的 DTLS 客户端应回复包含此 cookie 的新 ClientHello 消息。
- 当服务器收到包含 cookie 的 ClientHello 消息时,它会根据上述方法生成新的 cookie。
- 如果 cookie 相等,则认为客户端是真实的,然后服务器可以继续进行 TLS 握手过程。
注意:DTLS服务器不需要使用DTLS饼干。
QDtlsClientVerifier设计成与QUdpSocket配合使用,具体代码片段如下所示。
class DtlsServer : public QObject { public: bool listen(const QHostAddress &address, quint16 port); // ... private: void readyRead(); // ... QUdpSocket serverSocket; QDtlsClientVerifier verifier; // ... }; bool DtlsServer::listen(const QHostAddress &serverAddress, quint16 serverPort) { if (serverSocket.bind(serverAddress, serverPort)) connect(&serverSocket, &QUdpSocket::readyRead, this, &DtlsServer::readyRead); return serverSocket.state() == QAbstractSocket::BoundState; } void DtlsServer::readyRead() { QByteArray dgram(serverSocket.pendingDatagramSize(), Qt::Uninitialized); QHostAddress address; quint16 port = {}; serverSocket.readDatagram(dgram.data(), dgram.size(), &address, &port); if (verifiedClients.contains({address, port}) { // This client was verified previously, we either continue the // handshake or decrypt the incoming message. } else if (verifier.verifyClient(&serverSocket, dgram, address, port)) { // Apparently we have a real DTLS client who wants to send us // encrypted datagrams. Remember this client as verified // and proceed with a handshake. } else { // No matching cookie was found in the incoming datagram, // verifyClient() has sent a ClientVerify message. // We'll hear from the client again soon, if they're real. } }
QDtlsClientVerifier不限制应用如何使用QUdpSocket。例如,可以有一个服务器拥有一个处于QAbstractSocket::BoundState的单个QUdpSocket,同时处理多个DTLS客户端。
这意味着QDtlsClientVerifier不会直接从套接字读取,而是期望应用程序读取一个传入的数据报,提取发送者的地址和端口,然后将这些数据传递给verifyClient()。为了发送HelloVerifyRequest消息,verifyClient()可以写入到QUdpSocket。
注意:QDtlsClientVerifier不会拥有QUdpSocket对象。
默认情况下,QDtlsClientVerifier从密码学强伪随机数生成器中获得其密钥。
注意:默认密钥由QDtlsClientVerifier和QDtls类的所有对象共享。因为这可能会引起安全风险,RFC 6347建议频繁更改服务器的密钥。请参见RFC 6347,第4.2.1节中关于可能的服务器实现的说明。可以通过类QDtlsClientVerifier::GeneratorParameters和setCookieGeneratorParameters()设置饼干生成器的参数。
void DtlsServer::updateServerSecret() { const QByteArray newSecret(generateCryptoStrongSecret()); if (newSecret.size()) { usedCookies.append(newSecret); verifier.setCookieGeneratorParameters({QCryptographicHash::Sha1, newSecret}); } }
DTLS服务器示例说明了如何在服务器应用程序中使用QDtlsClientVerifier。
另请参阅QUdpSocket、QAbstractSocket::BoundState、QDtls、verifyClient()、GeneratorParameters、setCookieGeneratorParameters()、cookieGeneratorParameters()、QDtls::setCookieGeneratorParameters()、QDtls::cookieGeneratorParameters()、QCryptographicHash::Algorithm、QDtlsError、dtlsError()、和dtlsErrorString。
成员函数说明
[explicit]
QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent = nullptr)
构造一个QDtlsClientVerifier对象,parent被传递给QObject的构造函数。
[virtual noexcept]
QDtlsClientVerifier::~QDtlsClientVerifier()
销毁QDtlsClientVerifier对象。
QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorParameters() const
返回用于生成cookie的当前密钥和散列算法。如果Qt配置为支持,默认散列算法为QCryptographicHash::Sha256,否则为QCryptographicHash::Sha1。默认密钥来自后端特制的密码学强伪随机数生成器。
另请参阅 QCryptographicHash::Algorithm、QDtlsClientVerifier::GeneratorParameters 和 setCookieGeneratorParameters。
QDtlsError QDtlsClientVerifier::dtlsError() const
返回最后发生的错误或 QDtlsError::NoError。
另请参阅 QDtlsError 和 dtlsErrorString。
QString QDtlsClientVerifier::dtlsErrorString() const
返回最后错误的文本描述,或一个空字符串。
另请参阅 dtlsError。
bool QDtlsClientVerifier::setCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters ¶ms)
设置从 params 中的密码和密码散列算法。此 QDtlsClientVerifier 将使用这些内容生成 cookies。如果新密码的大小为零,则此函数返回 false
并且不更改 cookie 生成器参数。
注意: 密码应是一个密码学安全的字节序列。
另请参阅 QDtlsClientVerifier::GeneratorParameters、cookieGeneratorParameters 和 QCryptographicHash::Algorithm。
QByteArray QDtlsClientVerifier::verifiedHello() const
方便函数。返回已成功验证的最后 ClientHello 消息,或者如果没有完成验证,则返回一个空的 QByteArray。
另请参阅 verifyClient。
bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port)
socket 必须是一个有效的指针,dgram 必须是一个非空的数据报,address 不能为空、广播或多播。 port 是远程对等方的端口。如果 dgram 包含一个有效的 cookie 的 ClientHello 消息,则此函数返回 true
。如果没有找到匹配的 cookie,verifyClient() 将使用 socket 发送 HelloVerifyRequest 消息,并返回 false
。
以下示例显示了服务器应用程序如何检查错误
if (!verifier.verifyClient(&socket, message, address, port)) { switch (verifyClient.dtlsError()) { case QDtlsError::NoError: // Not verified yet, but no errors found and we have to wait for the next // message from this client. return; case QDtlsError::TlsInitializationError: // This error is fatal, nothing we can do about it. // Probably, quit the server after reporting the error. return; case QDtlsError::UnderlyingSocketError: // There is some problem in QUdpSocket, handle it (see QUdpSocket::error()) return; case QDtlsError::InvalidInputParameters: default: Q_UNREACHABLE(); } }
另请参阅 QHostAddress::isNull、QHostAddress::isBroadcast、QHostAddress::isMulticast、setCookieGeneratorParameters 和 cookieGeneratorParameters。
© 2024 The Qt Company Ltd. 本文件中包含的文档贡献是各自所有者的版权。在此提供的文档是根据 Free Software Foundation 发布的 GNU Free Documentation License 版本 1.3 的条款许可的。Qt 和相应的商标是 The Qt Company Ltd. 在芬兰和/或其他国家的商标。所有其他商标均为其各自所有者的财产。