从QsslServer::sslErrors调用QDialog::exec可以吗? (添加了可重现的示例)

问题描述 投票:0回答:1

我正在开发一个使用 SSL 套接字进行通信的应用程序,当不受信任的客户端连接到服务器时,它会发出 sslError 现在我应该使用 QDialog::exec() 询问用户决定(我可以'不进行异步操作,因为我需要处理 sslError 中的错误,无论是ignoreSslError还是中止连接取决于用户的决定)但是当我打开对话框时客户端已断开连接(客户端套接字似乎已被删除)然后QDialog exec在我访问时返回套接字它会抛出内存访问冲突错误。

Qt 文档QDialog::exec

注意:避免使用该功能;相反,使用 open()。与 exec() 不同,open() 是异步的,并且不会旋转额外的事件循环。这可以防止发生一系列危险的错误(例如,在通过 exec() 打开对话框时删除对话框的父级)。使用 open() 时,您可以连接到 QDialog 的 finish() 信号,以便在对话框关闭时收到通知。

遇到这种情况我该怎么办?

我有一个替代的身份验证过程,如果存在任何sslHandshakeErrors,则从连接开始,允许连接继续,然后如果用户按“确定”,我将异步显示对话框,我发送一个名为 authOk 的数据包并继续阅读,否则我发送一个名为 authFailed 的数据包并断开客户端连接。但在这个过程中,似乎没有使用标准的SSL连接握手。

有更好的解决方案吗,谢谢:)

编辑:

示例:


#include <QApplication>
#include <QSslServer>
#include <QDialog>
#include <QSslKey>
#include <QMessageBox>

int main(int argc, char **argv) {
  // create an Application
  QApplication app(argc, argv);

  // set the ssl configuration
  auto config = QSslConfiguration();

  // set certificate
  config.setLocalCertificate(QSslCertificate::fromData(QByteArray::fromStdString(R"(
-----BEGIN CERTIFICATE-----
MIIDITCCAgmgAwIBAgIVAMdt4c6oGd0rUSbR+/tBVfhny3K3MA0GCSqGSIb3DQEB
BQUAMEoxGDAWBgNVBAMMD0xBUFRPUC1KQzJNMzcyQTEbMBkGA1UECgwSc3JpbGFr
c2htaWthbnRoYW5wMREwDwYDVQQLDAhjbGlwYmlyZDAeFw0yMzA5MDgxMTQ4NDZa
Fw0yNDA5MDcxMTQ4NDZaMEoxGDAWBgNVBAMMD0xBUFRPUC1KQzJNMzcyQTEbMBkG
A1UECgwSc3JpbGFrc2htaWthbnRoYW5wMREwDwYDVQQLDAhjbGlwYmlyZDCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkFDUKmzz+NE0x7o5JGgE8KZ/cB
GEtTwN2cElMESQ/MZe3ohIE5GdFkld/7894wXZAJkXu38oZVEQ/AurntqqSHT4iP
7qMUJGYjo2v2g/1JwU3E/sG+IjatOjyl8b0b+E9TmDt7XOS4VWz3vjTkXwmQTzUv
3L5myfdcmBpA9AOXxH8yHq9lcBl97ZHGWA4zI9uWnwtyFWSl8DX4H/y14+itEYwH
n6xLsEBxqjx40G7WR0AiAYRdE5Yvr6QOGtFAeODFqOv/2sAxdm/7P1wHjIvyOB++
eufvPyWZpzeBfEvrIeGkj91YGAV7FQsOfCuzetGgZcLiBDAZKjnKEQ2oajUCAwEA
ATANBgkqhkiG9w0BAQUFAAOCAQEAD/SYccAb3K6GKyfc9Rbaj44IxpsNlHDQAr5b
c8Nmz+LW905EqFe6tAhCgi3q9o3HUUeiNHe0rYad3Lgd1setSOVdWiSbxArmELgW
Dg3NGd3GIIRShvmZfSHRkpvKaD9j06CVzMrM0nZsjQVcQrKlFBUJ9UEqVmmcz1nU
a4yUEQ9Rb7t4Icw7aD07NqLRlhNGCii4d12NAY7kRZdLdtTw7T/j4tXxmcJsOiWK
Lx/cqqTBgBHc3l3EeylQdO17pFClY5yMUGGla7LPcDm1sU4mmFEKmkjcRGu+mQM2
V3EDgh37GyTWvs6Zf86B14m/US0Ff4vQu26vco5Pjk3xKckA+Q==
-----END CERTIFICATE-----
)")).first());

  // set private key
  config.setPrivateKey(QSslKey(QByteArray::fromStdString(R"(
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAuQUNQqbPP40TTHujkkaATwpn9wEYS1PA3ZwSUwRJD8xl7eiE
gTkZ0WSV3/vz3jBdkAmRe7fyhlURD8C6ue2qpIdPiI/uoxQkZiOja/aD/UnBTcT+
wb4iNq06PKXxvRv4T1OYO3tc5LhVbPe+NORfCZBPNS/cvmbJ91yYGkD0A5fEfzIe
r2VwGX3tkcZYDjMj25afC3IVZKXwNfgf/LXj6K0RjAefrEuwQHGqPHjQbtZHQCIB
hF0Tli+vpA4a0UB44MWo6//awDF2b/s/XAeMi/I4H7565+8/JZmnN4F8S+sh4aSP
3VgYBXsVCw58K7N60aBlwuIEMBkqOcoRDahqNQIDAQABAoIBADf6I0zrEwDzOceG
ELMMyX0gdNvyZNtFd7CUq6aaQVCaUqxsEMrX78u+VunxXJL4pxYRDwcTXDjwO708
XkIqedpVZea3RUfprCmK1sKvTrevPOC+nSUY1Vkdh+UZf83rTHETpZc5d51rd80E
F3QBNA+8rXo2BN9GUgyY4xvuUuVS3drVZ6WA9A9yPtaBgeLATqmb0Ckh2aVn+XG9
eYIxiF0Sfnb3HET7IDO+Xtw8OIygq+dT9v5LMMYf/Aa8aakJMoTK6SLbjFWs5gUj
mhBSBdxqdmLLTa2E+3hrZOfgQ0tk85336n7v3dFKkhTMr9KztOIh53Ruh36gR3UT
QxbCyvECgYEA2uKcFmrkGa61WarqSbB58e/m111cmlcjOSoEELwb+O1pLe8qqDSZ
UeLVMRW+omdyvt0N1RaDEOsBWtgup2RntutEx8sAi5O1d+CrCLZ7xZJPSrYH4tIs
YFXoBgCNqn+275ZdeL5LgxuFKAstFW9YbWpsXCEPbrIMBk4Xm3m3Pt8CgYEA2GRo
I+lLPvcslTwens+5sXT5+EPTcY9Ss2jSz3njEIt4asxa/P4H7Xx2EWqMQg5LGSVD
MP8L9lxCSiyYvrQhYAQZq2VqvVCejFkrWY8hntDvyhJ26SfanSdMB1MVWOc16dns
wjuuX3+5QIQoMogL1eng6/VOOJHVfiAh57yqPWsCgYEAkcI54wvHXfrjtRSF9BBb
BGuXM29ujTDdueFq16IMlpWyZu5PX7e3Kbp98bPjQM7WsJcP8QiOuyNjwZUYbEwG
bN767HkYodn5DB1GiATNI2Is/zl8wuTmvDg4zFZuAE4QCjf9grxmGKao42Od4BpH
roUiJ6+0USirrT8vpU9GYc0CgYAYuIfJKnrFK7m1JtQcsoB1THbOLPl37La29k+3
EialmjlcghIW+vJu6BwY60Iwva9IpSAi9dApCesszCF7D9sMPAuur/xculwSjpFM
PvTJTvdF74wUINBxya5+27gBmxBmsdXBbs4B7PZ971skQrSPcJOYgUK5ZbetHACj
l8MfFwKBgQC3g39rKU/iahrr5VcbLecsdv9jhSo+PANQOXhreEZTOF1spsWh9bMN
11MB0uZu99p4Solvv0M11Md++CO3ocBRT0AsdsdLdytAb+YWM+c1ls5dhjVnaMpL
dKKHiQ7sfiPM05f6HuTmMuinSLw7f1Ff7GVJUMugJCqiNn3XO3jWGQ==
-----END RSA PRIVATE KEY-----
)"), QSsl::KeyAlgorithm::Rsa));

  // peer verify
  config.setPeerVerifyMode(QSslSocket::VerifyPeer);

  // if any of them is null
  if (config.isNull() || config.localCertificate().isNull() || config.privateKey().isNull()) {
    throw std::runtime_error("Can't Create QSslConfiguration");
  }

  const auto processSslErrors = [=] (QSslSocket * sock, const QList<QSslError> & errors){
    // create a dialog
    auto dialog = QMessageBox(QMessageBox::Critical, "SSL Error", "Accept ?", QMessageBox::Yes | QMessageBox::Cancel);

    // show the dialog
    dialog.exec();

    // if user accepted
    if (dialog.result() == QMessageBox::Yes) {
      sock->ignoreSslErrors();
    }
  };

  // create the server
  auto server = new QSslServer();

  // set the ssl errors handler
  QObject::connect(server, &QSslServer::sslErrors, processSslErrors);

  // set the ssl configuration
  server->setSslConfiguration(config);

  // listen to the port
  server->listen(QHostAddress::Any, 7000);

  // exec
  return app.exec();
}

例外:

在客户端:

openssl s_client -connect 127.0.0.1:7000

当对话框打开时,您可以看到客户端已断开连接

c++ qt authentication ssl network-programming
1个回答
-2
投票

您正在处理这样一种情况:您需要在 Qt 应用程序的握手过程中处理 SSL 错误,并与用户交互以根据这些错误做出决策。在这种情况下使用 QDialog::exec() 是有问题的,因为它会阻塞事件循环,并且您希望避免阻塞事件循环以防止出现您所描述的问题。

我的建议是为身份验证对话框使用单独的线程。

© www.soinside.com 2019 - 2024. All rights reserved.