Qt网络编程:QDtlsClientVerifier

一、描述

QDtlsClientVerifier 类实现服务器端 DTLS cookie 生成和验证。

数据报安全协议极易受到各种拒绝服务攻击。两种常见的攻击类型:

  • 攻击者发送一系列握手发起请求,导致服务器分配过多资源并可能执行昂贵的加密操作。
  • 攻击者使用受害者的伪造源发送一系列握手发起请求,使服务器充当放大器。通常,服务器会用一个证书消息回复受害机器,该消息可能非常大,从而使受害机器充满数据报。

作为对这些攻击的对策,可以使用一种服务器可以部署的无状态 cookie 技术:

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

可访问的 DTLS 客户端应使用包含此 cookie 的新 ClientHello 消息进行回复。

当服务器收到带有 cookie 的 ClientHello 消息时,它会生成一个新的 cookie。将此新 cookie 与在 ClientHello 消息中找到的 cookie 进行比较。在 cookie 相等的情况下,客户端被认为是真实的,服务器可以继续进行 TLS 握手过程。

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}) 
     {
          // 这个客户端之前已经验证过了,继续握手或解密传入的消息。
     }
     else if (verifier.verifyClient(&serverSocket, dgram, address, port)) 
     {
          // 有一个真正的 DTLS 客户端想要向我们(服务端)发送加密数据报。记住此客户端已验证并继续握手。
     } 
     else 
     {
          // 在传入的数据报中没有找到匹配的 cookie,verifyClient() 已经发送了一个 ClientVerify 消息。 如果他们是真的,服务端很快就会再次收到客户的消息,
     }
 }

QDtlsClientVerifier 不会对应用程序如何使用 QUdpSocket 施加任何限制。这意味着 QDtlsClientVerifier 不直接从socket读取,而是期望应用程序读取传入的数据报,提取发送者的地址和端口,然后将此数据传递给 verifyClient()。

注意:默认密钥由 QDtlsClientVerifier 和 QDtls 类的所有对象共享。

可以使用类 GeneratorParameters() 和 setCookieGeneratorParameters() 设置 Cookie 生成器参数:

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

二、GeneratorParameters结构体

此结构体的对象提供 QDtlsClientVerifier 用于生成 DTLS cookie 的参数。包括加密哈希算法和secret。


三、成员函数

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

设置将用来生成cookie的GeneratorParameters 对象。如果GeneratorParameters 对象的secret大小为零,则此函数返回 false 并且不会更改 cookie 生成器参数。 

2、QByteArray verifiedHello()

返回最后一个成功验证的 ClientHello 消息。

 3、bool verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port)

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

以下代码段显示了服务器应用程序如何检查错误:

 if (!verifier.verifyClient(&socket, message, address, port)) {
     switch (verifyClient.dtlsError()) {
     case QDtlsError::NoError:
          // 还没有验证,但是没有发现错误,等待下一个来自这个客户端的消息。         
          return;
     case QDtlsError::TlsInitializationError:
          // 这个错误是致命的,我们无能为力。 可能报错后退出服务器。
          return;
     case QDtlsError::UnderlyingSocketError:
          // QUdpSocket有问题,处理(参见QUdpSocket::error())
          return;
     case QDtlsError::InvalidInputParameters:
     default:
         Q_UNREACHABLE();
     }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值