This class implements server-side DTLS cookie generation and verification. 更多...
头: | #include <QDtlsClientVerifier> |
CMake: |
find_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(mytarget PRIVATE Qt6::Network) |
qmake: | QT += network |
继承: | QObject |
struct | GeneratorParameters |
QDtlsClientVerifier (QObject * parent = nullptr) | |
virtual | ~QDtlsClientVerifier () |
QDtlsClientVerifier::GeneratorParameters | cookieGeneratorParameters () const |
QDtlsError | dtlsError () const |
QString | dtlsErrorString () const |
bool | setCookieGeneratorParameters (const QDtlsClientVerifier::GeneratorParameters & params ) |
QByteArray | verifiedHello () const |
bool | verifyClient (QUdpSocket * socket , const QByteArray & dgram , const QHostAddress & address , quint16 port ) |
The QDtlsClientVerifier class implements server-side DTLS cookie generation and verification. Datagram security protocols are highly susceptible to a variety of Denial-of-Service attacks. According to RFC 6347, section 4.2.1 , these are two of the more common types of attack:
As a countermeasure to these attacks, RFC 6347, section 4.2.1 proposes a stateless cookie technique that a server may deploy:
注意: A DTLS server is not required to use DTLS cookies.
QDtlsClientVerifier is designed to work in pair with QUdpSocket , as shown in the following code-excerpt:
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 does not impose any restrictions on how the application uses QUdpSocket . For example, it is possible to have a server with a single QUdpSocket in state QAbstractSocket::BoundState , handling multiple DTLS clients simultaneously:
This implies that QDtlsClientVerifier does not read directly from a socket, instead it expects the application to read an incoming datagram, extract the sender's address, and port, and then pass this data to verifyClient (). To send a HelloVerifyRequest message, verifyClient () can write to the QUdpSocket .
注意: QDtlsClientVerifier does not take ownership of the QUdpSocket 对象。
By default QDtlsClientVerifier obtains its secret from a cryptographically strong pseudorandom number generator.
注意: The default secret is shared by all objects of the classes QDtlsClientVerifier and QDtls . Since this can impose security risks, RFC 6347 recommends to change the server's secret frequently. Please see RFC 6347, section 4.2.1 for hints about possible server implementations. Cookie generator parameters can be set using the class QDtlsClientVerifier::GeneratorParameters and setCookieGeneratorParameters ():
void DtlsServer::updateServerSecret() { const QByteArray newSecret(generateCryptoStrongSecret()); if (newSecret.size()) { usedCookies.append(newSecret); verifier.setCookieGeneratorParameters({QCryptographicHash::Sha1, newSecret}); } }
The DTLS 服务器 example illustrates how to use QDtlsClientVerifier in a server application.
另请参阅 QUdpSocket , QAbstractSocket::BoundState , QDtls , verifyClient (), GeneratorParameters , setCookieGeneratorParameters (), cookieGeneratorParameters (), QDtls::setCookieGeneratorParameters (), QDtls::cookieGeneratorParameters (), QCryptographicHash::Algorithm , QDtlsError , dtlsError (),和 dtlsErrorString ().
[explicit]
QDtlsClientVerifier::
QDtlsClientVerifier
(
QObject
*
parent
= nullptr)
Constructs a QDtlsClientVerifier object, parent 会被传递给 QObject 的构造函数。
[virtual noexcept]
QDtlsClientVerifier::
~QDtlsClientVerifier
()
销毁 QDtlsClientVerifier 对象。
Returns the current secret and hash algorithm used to generate cookies. The default hash algorithm is QCryptographicHash::Sha256 if Qt was configured to support it, QCryptographicHash::Sha1 otherwise. The default secret is obtained from the backend-specific cryptographically strong pseudorandom number generator.
另请参阅 QCryptographicHash::Algorithm , QDtlsClientVerifier::GeneratorParameters ,和 setCookieGeneratorParameters ().
Returns the last error that occurred or QDtlsError::NoError .
另请参阅 QDtlsError and dtlsErrorString ().
Returns a textual description of the last error, or an empty string.
另请参阅 dtlsError ().
Sets the secret and the cryptographic hash algorithm from
params
。此
QDtlsClientVerifier
will use these to generate cookies. If the new secret has size zero, this function returns
false
and does not change the cookie generator parameters.
注意: The secret is supposed to be a cryptographically secure sequence of bytes.
另请参阅 QDtlsClientVerifier::GeneratorParameters , cookieGeneratorParameters (),和 QCryptographicHash::Algorithm .
Convenience function. Returns the last ClientHello message that was successfully verified, or an empty QByteArray if no verification has completed.
另请参阅 verifyClient ().
socket
must be a valid pointer,
dgram
must be a non-empty datagram,
address
cannot be null, broadcast, or multicast.
port
is the remote peer's port. This function returns
true
if
dgram
contains a ClientHello message with a valid cookie. If no matching cookie is found, verifyClient() will send a HelloVerifyRequest message using
socket
并返回
false
.
The following snippet shows how a server application may check for errors:
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 ().