class QDtlsClientVerifier#

此类实现了服务器端 DTLS 曲奇生成和验证。 更多信息...

Inheritance diagram of PySide6.QtNetwork.QDtlsClientVerifier

简介#

方法#

本文档可能包含自动从C++翻译到Python的代码片段。我们始终欢迎对片段翻译的贡献。如果您发现翻译问题,也可以通过在https:/bugreports.qt.io/projects/PYSIDE上创建工单来通知我们

详细描述#

注意

本节包含自动从C++翻译到Python的代码片段,可能存在错误。

QDtlsClientVerifier类实现了服务器端DTLS cookie的生成和验证。数据报安全协议容易受到各种拒绝服务攻击。根据RFC 6347,第4.2.1节,以下是两种更常见的攻击类型

  • 攻击者发送一系列握手初始化请求,导致服务器分配过多的资源,并可能执行昂贵的加密操作。

  • 攻击者使用受害者的伪造源发送一系列握手初始化请求,使服务器充当放大器。通常,服务器会向受害者机器回复证书消息,这可能相当大,因此会向受害者机器发送大量数据报。

作为一种对抗这些攻击的对策,RFC 6347第4.2.1节提出了一种服务器可能部署的无状态cookie技术

  • 针对初始的ClientHello消息,服务器发送包含cookie的HelloVerifyRequest。这个cookie是一个加密散列,使用客户端的地址、端口号和服务器私钥(这是一个字节的加密强伪随机序列)生成。

  • 可到达的DTLS客户端应回复包含此cookie的新ClientHello消息。

  • 当服务器收到包含cookie的ClientHello消息时,它将按照上述方式生成一个新的cookie。这个新cookie与ClientHello消息中找到的cookie进行比较。

  • 如果cookie相同,则认为客户端是真实的,服务器可以继续使用TLS握手进程。

DTLS服务器不必要使用DTLS cookies。

QDtlsClientVerifier设计为与QUdpSocket 配对工作,如下面的代码示例所示

class DtlsServer(QObject):

# public
    listen = bool(QHostAddress address, quint16 port)
    # ...
# private
    def readyRead():
    # ...
    serverSocket = QUdpSocket()
    verifier = QDtlsClientVerifier()
    # ...

def listen(self, QHostAddress serverAddress, quint16 serverPort):

    if serverSocket.bind(serverAddress, serverPort):
        serverSocket.readyRead.connect(self.readyRead)
    return serverSocket.state() == QAbstractSocket.BoundState

def readyRead(self):

    dgram = QByteArray(serverSocket.pendingDatagramSize(), Qt.Uninitialized)
    address = QHostAddress()
    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.
     elif 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 没有任何限制。例如,可以有一个服务器,它有一个处于 BoundState 状态的单个 QUdpSocket 处理多个同时连接的 DTLS 客户端。

  • 测试新客户端是否是真实的 DTLS 兼容客户端。

  • 完成与验证客户的 TLS 握手(见 QDtls )。

  • 解密来自连接客户端的数据报(见 QDtls )。

  • 向连接的客户端发送加密数据报(见 QDtls )。

这意味着 QDtlsClientVerifier 不会直接从套接字读取,相反它期望应用程序读取进入的数据报,提取发送者的地址和端口,然后将这些数据传递给 verifyClient() 方法。要发送 HelloVerifyRequest 消息,verifyClient() 可以写入 QUdpSocket

QDtlsClientVerifier 不会获取 QUdpSocket 对象的所有权。

默认情况下,QDtlsClientVerifier 从加密强伪随机数生成器获取其密钥。

默认密钥在 QDtlsClientVerifierQDtls 类的所有对象中共享。由于这可能会带来安全风险,RFC 6347 建议频繁更改服务器的密钥。请参阅 RFC 6347 第 4.2.1 节中有关可能的实现方法。可以使用 GeneratorParameters 类和 setCookieGeneratorParameters() 方法设置 Cookie 生成器参数。

def updateServerSecret(self):

    newSecret = QByteArray(generateCryptoStrongSecret())
    if newSecret.size():
        usedCookies.append(newSecret)
        verifier.setCookieGeneratorParameters({QCryptographicHash.Sha1, newSecret})

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

另请参阅

QUdpSocketBoundState 结合 QDtls 使用 verifyClient(),包括 GeneratorParameterssetCookieGeneratorParameters()cookieGeneratorParameters()cookieGeneratorParameters()QDtlsErrordtlsError()dtlsErrorString()

__init__([parent=None])#
参数:

parentQObject

构造 QDtlsClientVerifier 对象,parent 传递给 QObject 构造函数。

dtlsError()#
返回类型:

QDtlsError

返回最近发生的错误,或 NoError

另请参阅

QDtlsError dtlsErrorString()

dtlsErrorString()#
返回类型:

str

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

另请参阅

dtlsError()

verifiedHello()#
返回类型:

QByteArray

便捷函数。返回最后成功验证的 ClientHello 消息,或者在未完成验证的情况下返回空的 QByteArray。

另请参阅

verifyClient()

verifyClient(socket, dgram, address, port)#
参数:
返回类型:

bool

注意

本节包含自动从C++翻译到Python的代码片段,可能存在错误。

socket必须是一个有效的指针,dgram必须是一个非空的报文,address不能为空、广播或多播。port是远程对等机的端口。此函数返回true,如果dgram包含有效cookie的ClientHello消息。如果没有找到匹配的cookie,verifyClient()会使用socket发送HelloVerifyRequest消息,并返回false

以下代码片段展示了服务器程序如何检查错误

if not verifier.verifyClient(socket, message, address, port):
    switch (verifyClient.dtlsError()) {
    elif ret == QDtlsError.NoError:
        # Not verified yet, but no errors found and we have to wait for the next
        # message from this client.
        return
    elif ret == QDtlsError.TlsInitializationError:
        # This error is fatal, nothing we can do about it.
        # Probably, quit the server after reporting the error.
        return
    elif ret == QDtlsError.UnderlyingSocketError:
        # There is some problem in QUdpSocket, handle it (see QUdpSocket::error())
        return
    elif ret == QDtlsError.InvalidInputParameters:
    else:
        Q_UNREACHABLE()

另请参阅

isNull() isBroadcast() isMulticast() setCookieGeneratorParameters() cookieGeneratorParameters()