QDtlsClientVerifier 类

此类实现了服务器端 DTLS 协议的 cookie 生成和验证。 更多...

头文件 #include <QDtlsClientVerifier>
CMakefind_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(mytarget PRIVATE Qt6::Network)
qmakeQT += network
继承 QObject

公共类型

公共函数

QDtlsClientVerifier(QObject *parent = nullptr)
虚拟~QDtlsClientVerifier()
QDtlsClientVerifier::GeneratorParameterscookieGeneratorParameters() const
QDtlsErrordtlsError() const
QStringdtlsErrorString() const
boolsetCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters &params)
QByteArrayverifiedHello() const
boolverifyClient(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客户端。

  • 测试新客户端是否为真正的DTLS功能客户端。
  • 与经过验证的客户端完成TLS握手(见QDtls)。
  • 解密来自连接客户端的数据报(见QDtls)。
  • 向连接的客户端发送加密数据报(见QDtls)。

这意味着QDtlsClientVerifier不会直接从套接字读取,而是期望应用程序读取一个传入的数据报,提取发送者的地址和端口,然后将这些数据传递给verifyClient()。为了发送HelloVerifyRequest消息,verifyClient()可以写入到QUdpSocket

注意:QDtlsClientVerifier不会拥有QUdpSocket对象。

默认情况下,QDtlsClientVerifier从密码学强伪随机数生成器中获得其密钥。

注意:默认密钥由QDtlsClientVerifier和QDtls类的所有对象共享。因为这可能会引起安全风险,RFC 6347建议频繁更改服务器的密钥。请参见RFC 6347,第4.2.1节中关于可能的服务器实现的说明。可以通过类QDtlsClientVerifier::GeneratorParameterssetCookieGeneratorParameters()设置饼干生成器的参数。

void DtlsServer::updateServerSecret()
{
    const QByteArray newSecret(generateCryptoStrongSecret());
    if (newSecret.size()) {
        usedCookies.append(newSecret);
        verifier.setCookieGeneratorParameters({QCryptographicHash::Sha1, newSecret});
    }
}

DTLS服务器示例说明了如何在服务器应用程序中使用QDtlsClientVerifier。

另请参阅QUdpSocketQAbstractSocket::BoundStateQDtlsverifyClient()、GeneratorParameterssetCookieGeneratorParameters()、cookieGeneratorParameters()、QDtls::setCookieGeneratorParameters()、QDtls::cookieGeneratorParameters()、QCryptographicHash::AlgorithmQDtlsErrordtlsError()、和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::AlgorithmQDtlsClientVerifier::GeneratorParameterssetCookieGeneratorParameters

QDtlsError QDtlsClientVerifier::dtlsError() const

返回最后发生的错误或 QDtlsError::NoError

另请参阅 QDtlsErrordtlsErrorString

QString QDtlsClientVerifier::dtlsErrorString() const

返回最后错误的文本描述,或一个空字符串。

另请参阅 dtlsError

bool QDtlsClientVerifier::setCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters &params)

设置从 params 中的密码和密码散列算法。此 QDtlsClientVerifier 将使用这些内容生成 cookies。如果新密码的大小为零,则此函数返回 false 并且不更改 cookie 生成器参数。

注意: 密码应是一个密码学安全的字节序列。

另请参阅 QDtlsClientVerifier::GeneratorParameterscookieGeneratorParametersQCryptographicHash::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::isNullQHostAddress::isBroadcastQHostAddress::isMulticastsetCookieGeneratorParameterscookieGeneratorParameters

© 2024 The Qt Company Ltd. 本文件中包含的文档贡献是各自所有者的版权。在此提供的文档是根据 Free Software Foundation 发布的 GNU Free Documentation License 版本 1.3 的条款许可的。Qt 和相应的商标是 The Qt Company Ltd. 在芬兰和/或其他国家的商标。所有其他商标均为其各自所有者的财产。