Класс QDtlsClientVerifier
Этот класс реализует генерацию и проверку куки DTLS на стороне сервера. Подробнее...
| Заголовок: | #include <QDtlsClientVerifier> |
| CMake: | find_package(Qt6 COMPONENTS Network REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Network) |
| qmake: | QT += network |
| С тех пор: | Qt 5.12 |
| Наследуется от: | QObject |
Публичные типы
| Структура | GeneratorParameters |
Публичные функции
| 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 на стороне сервера. Протоколы безопасности датаграмм очень уязвимы к различным атакам типа «отказ в обслуживании». Согласно RFC 6347, раздел 4.2.1, вот два наиболее распространённых типа таких атак:
- Злоумышленник отправляет серию запросов на инициирование рукопожатия, заставляя сервер выделять чрезмерные ресурсы и потенциально выполнять дорогостоящие криптографические операции.
- Злоумышленник отправляет серию запросов на инициирование рукопожатия с поддельным источником жертвы, заставляя сервер действовать как усилитель. Обычно сервер отвечает машине-жертве сообщением Certificate, которое может быть довольно большим, тем самым перегружая машину-жертву датаграммами.
В качестве противодействия этим атакам RFC 6347, раздел 4.2.1 предлагает использовать бессостоятельный метод куки, который может использовать сервер:
- В ответ на начальное сообщение ClientHello сервер отправляет HelloVerifyRequest, содержащий куки. Эта куки — криптографический хэш, генерируемый с использованием адреса клиента, номера порта и секрета сервера (который является криптографически надёжной псевдослучайной последовательностью байтов).
- От клиента DTLS ожидается ответ с новым сообщением ClientHello, содержащим эту куки.
- Когда сервер получает сообщение ClientHello с куки, он генерирует новую куки, как описано выше. Эта новая куки сравнивается с куки в сообщении ClientHello.
- Если куки совпадают, клиент считается реальным, и сервер может продолжить процедуру рукопожатия 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. Например, возможно иметь сервер с одним QUdpSocket в состоянии QAbstractSocket::BoundState, обрабатывающий одновременно нескольких клиентов DTLS:
- Проверка, являются ли новые клиенты реальными клиентами, поддерживающими DTLS.
- Завершение рукопожатий TLS с проверенными клиентами (см. QDtls).
- Расшифровка датаграмм, поступающих от подключённых клиентов (см. QDtls).
- Отправка зашифрованных датаграмм подключённым клиентам (см. QDtls).
Это подразумевает, что 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().
Документация по функциям-членам
QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent = nullptr)
Создаёт объект QDtlsClientVerifier, parent передаётся в конструктор QObject.
[virtual] QDtlsClientVerifier::~QDtlsClientVerifier()
Уничтожает объект QDtlsClientVerifier.
QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorParameters() const
Возвращает текущий секрет и алгоритм хеширования, используемые для генерации куки. Алгоритм хеширования по умолчанию — QCryptographicHash::Sha256, если Qt настроен на его поддержку, в противном случае — 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 будет использовать их для генерации куки. Если новый секрет имеет нулевой размер, эта функция возвращает false и не изменяет параметры генератора куки.
Примечание: Секрет должен быть криптографически надёжной последовательностью байтов.
См. также 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 — не null, не широковещательной и не многоадресной. port — порт удалённого узла. Эта функция возвращает true если dgram содержит сообщение ClientHello с корректным куки. Если соответствующего куки не найдено, verifyClient() отправит сообщение HelloVerifyRequest с использованием socket и вернёт 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().
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qdtlsclientverifier.html