配置QSslConfiguration让客户端程序跳过本地SSL验证



  • 大家下午好哦。今天我们在重新制作我们萌梦聊天室的时候,出现了这样的问题。那就是我们的客户端能够对qtdream.com服务器进行登录,但是不能对localhost服务器(也就是本机啦)进行登录。这究竟是什么原因呢?
    原图来自http://www.pixiv.net/member_illust.php?mode=medium&illust_id=60269167
    因为这个问题是在我们引入了https的时候出现的,所以我们把原因定位到为什么会导致https出现问题。后面我看到了QNetworkRequest这个类,看到了里面有这样一个函数:🍓

    QNetworkRequest::setSslConfiguration(const QSslConfiguration &configuration);
    

    这个函数呢,可以设置SSL的配置,包括OpenSSL以及其它的SSL,都是这样的配置。然后我又看QSslConfiguration这个类:,并且看到了这样的函数:

    QSslSocket::setPeerVerifyMode(QSslSocket::PeerVerifyMode mode);
    

    我在仔细研读文档后,发现其中的端倪。原来默认设置是对服务器的安全证书进行验证的。我们本地的网站由于证书有问题,从而无法导入证书,这个时候呢,无法通过验证。这个时候,默认的验证模式无法通过,从而服务端无法获得到客户端传入的数据,因此我们需要进行这样的操作:

        // 设置SSL配置
        QSslConfiguration sslConf;
        sslConf.setPeerVerifyMode( QSslSocket::VerifyNone );
        r.setSslConfiguration( sslConf );
    

    这样操作的话,我们就可以不再检测SSL了。这样我们就可以顺利地通过我们的客户端连接到我们的服务器了。怎样?很简单吧。



  • 既然是VerifyNone,那还要QSslConfiguration干什么?完全去掉QSslConfiguration可以吗?



  • @stlcours 因为不配置这个,会采用默认的配置,导致我的聊天室软件连不上我的https的服务器。



  • 所以只是对本机登录不行的。对远程登录https://qtdream.com这边儿是可以的。



  • @jiangcaiyang123 你好,我正在学习QWebSocket编程,跟着示例做了服务器和客户端,服务器设置了VerifyNone,也生成了证书。客户端没有生成证书,因为服务器端设置了verifyNone。然后在同一台机器上运行测试,也就是这里所说的客户端连接本地服务器,但是客户端的state一直停留在connectingState,服务器端没有任何回馈,然后就一直这个状态,没有后续,没有emit任何错误。
    1.试过在客户端设置VerifyNone,无效
    2.试过在客户端生成证书,也无效
    3.试过非安全模式,成功,但没意义。

    困扰好几天了,请问你是怎么建立连接的?望指教

    平台是mac os sierra
    附上我的代码:
    服务器端:
    #include "fd_sslwebsocket_server.h"

    #include "fd_sslwebsocket_server.h"
    #include "QtWebSockets/QWebSocketServer"
    #include "QtWebSockets/QWebSocket"
    #include <QtCore/QDebug>
    #include <QtCore/QFile>
    #include <QtNetwork/QSslCertificate>
    #include <QtNetwork/QSslKey>

    QT_USE_NAMESPACE

    fd_sslwebsocket_server::fd_sslwebsocket_server(quint16 port, QObject *parent) :
    QObject(parent),
    m_pWebSocketServer(Q_NULLPTR),
    m_clients()
    {
    m_pWebSocketServer = new QWebSocketServer(QStringLiteral("SSL Echo Server"),
    QWebSocketServer::SecureMode,
    this);

      QSslConfiguration sslConfiguration;
      QFile certFile(QStringLiteral(":/ssl/test/CARoot1024.cert"));
      QFile keyFile(QStringLiteral(":/ssl/test/CARoot1024.key"));
      certFile.open(QIODevice::ReadOnly);
      keyFile.open(QIODevice::ReadOnly);
      QSslCertificate certificate(&certFile, QSsl::Pem);
      QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
      certFile.close();
      keyFile.close();
      sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
      sslConfiguration.setLocalCertificate(certificate);
      sslConfiguration.setPrivateKey(sslKey);
      sslConfiguration.setProtocol(QSsl::TlsV1SslV3);
      m_pWebSocketServer->setSslConfiguration(sslConfiguration);
    
    
      if (m_pWebSocketServer->listen(QHostAddress::Any, port))
      {
          qDebug() << "SSL Echo Server listening on port" << port;
          connect(m_pWebSocketServer, &QWebSocketServer::newConnection,
                  this, &fd_sslwebsocket_server::onNewConnection);
          connect(m_pWebSocketServer, &QWebSocketServer::sslErrors,
                  this, &fd_sslwebsocket_server::onSslErrors);
          connect(m_pWebSocketServer, &QWebSocketServer::peerVerifyError,
                  this, &fd_sslwebsocket_server::onPeerVerifyError);
      }
    

    }

    void fd_sslwebsocket_server::onPeerVerifyError(const QSslError &error)
    {
    qDebug() << error;
    }

    fd_sslwebsocket_server::~fd_sslwebsocket_server()
    {
    m_pWebSocketServer->close();
    qDeleteAll(m_clients.begin(), m_clients.end());
    }

    void fd_sslwebsocket_server::onNewConnection()
    {
    QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();

      qDebug() << "Client connected:" << pSocket->peerName() << pSocket->origin();
    
      connect(pSocket, &QWebSocket::textMessageReceived, this, &fd_sslwebsocket_server::processTextMessage);
      connect(pSocket, &QWebSocket::binaryMessageReceived,
              this, &fd_sslwebsocket_server::processBinaryMessage);
      connect(pSocket, &QWebSocket::disconnected, this, &fd_sslwebsocket_server::socketDisconnected);
      //connect(pSocket, &QWebSocket::pong, this, &fd_sslwebsocket_server::processPong);
    
      m_clients << pSocket;
    

    }

    void fd_sslwebsocket_server::processTextMessage(QString message)
    {
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
    qDebug() << "Received message:" << message;
    if (pClient)
    {
    pClient->sendTextMessage(message);
    }
    }

    void fd_sslwebsocket_server::processBinaryMessage(QByteArray message)
    {
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
    if (pClient)
    {
    pClient->sendBinaryMessage(message);
    }
    }

    void fd_sslwebsocket_server::socketDisconnected()
    {
    qDebug() << "Client disconnected";
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
    if (pClient)
    {
    m_clients.removeAll(pClient);
    pClient->deleteLater();
    }
    }

    void fd_sslwebsocket_server::onSslErrors(const QList<QSslError> &)
    {
    qDebug() << "Ssl errors occurred";
    }


    客户端:
    #include "fd_sslwebsocket_client.h"
    #include <QtCore/QDebug>
    #include <QtWebSockets/QWebSocket>
    #include <QCoreApplication>

    #include <QtCore/QFile>
    #include <QtNetwork/QSslCertificate>
    #include <QtNetwork/QSslKey>

    QT_USE_NAMESPACE

    fd_sslwebsocket_client::fd_sslwebsocket_client(const QUrl &url, QObject *parent) :
    QObject(parent),
    m_webSocket()
    {

    /*
    QSslConfiguration sslConfiguration;

      QFile certFile(QStringLiteral(":/ssl/test/CARoot1024.cert"));
      QFile keyFile(QStringLiteral(":/ssl/test/CARoot1024.key"));
      certFile.open(QIODevice::ReadOnly);
      keyFile.open(QIODevice::ReadOnly);
      QSslCertificate certificate(&certFile, QSsl::Pem);
      QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
      certFile.close();
      keyFile.close();
    
      sslConfiguration.setLocalCertificate(certificate);
      sslConfiguration.setPrivateKey(sslKey);
    
      sslConfiguration.setProtocol(QSsl::TlsV1SslV3);
      sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
      m_webSocket.setSslConfiguration(sslConfiguration);
    

    */

      connect(&m_webSocket, &QWebSocket::connected, this, &fd_sslwebsocket_client::onConnected);
    
      connect(&m_webSocket, static_cast<void(QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error), this,  &fd_sslwebsocket_client::onError);
    
      typedef void (QWebSocket:: *sslErrorsSignal)(const QList<QSslError> &);
      connect(&m_webSocket, static_cast<sslErrorsSignal>(&QWebSocket::sslErrors),
              this, &fd_sslwebsocket_client::onSslErrors);
    
      connect(&m_webSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
                        this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
    
      m_webSocket.open(QUrl(url));
      qDebug() << "Starting open..." << url;
    

    }

    void fd_sslwebsocket_client::socketStateChanged(QAbstractSocket::SocketState state)
    {
    qDebug() << "state:" << state;
    }

    void fd_sslwebsocket_client::onError(QAbstractSocket::SocketError error)
    {
    qDebug() << "error code:" << error << ". error string" << m_webSocket.errorString();
    }

    void fd_sslwebsocket_client::onConnected()
    {

      qDebug() << "WebSocket connected";
      connect(&m_webSocket, &QWebSocket::textMessageReceived,
              this, &fd_sslwebsocket_client::onTextMessageReceived);
    
      m_webSocket.sendTextMessage(QStringLiteral("Hello, world!"));
    
      int lv_count = 0;
      while (lv_count < 10000) {
          m_webSocket.sendTextMessage(QStringLiteral("Hello, world!") + QString::number(lv_count, 10));
          lv_count++;
      }
      qApp->quit();
    

    }

    void fd_sslwebsocket_client::onTextMessageReceived(QString message)
    {
    qDebug() << "Message received:" << message;
    //qApp->quit();
    }

    void fd_sslwebsocket_client::onSslErrors(const QList<QSslError> &errors)
    {
    Q_UNUSED(errors);

      // WARNING: Never ignore SSL errors in production code.
      // The proper way to handle self-signed certificates is to add a custom root
      // to the CA store.
    
      qDebug() << m_webSocket.errorString();
    
      //m_webSocket.ignoreSslErrors();
    

    }



  • @shwth33 用SSL的key和cer来验证的吗?这个我没有尝试过,我好像只是用open(),没有那么复杂的样子啊。



  • @shwth33 你可以在客户端里嵌入一个证书试试。



  • @stlcours 这个问题估计2018年还会出现,我们层经做过静态编译带聊天,曾经实现了,现在由于架构更改了,可能问题又是一大堆吧。


 

走马观花

最近的回复

  • @chinasmu Webkit网络的部分可能不是受到Qt控制的,扩展性较差,所以呢,还不能通过代码的方式侦听网络收发数据。但是WebEngine就可以。如果可以的话,试试Qt WebEngine。😺

    阅读更多
  • C

    我用qt建了个对话框程序,里面加了个webkit,请问有办法获取该控件的全部网络封包通信数据吗?
    不采用windows hook recv和send函数的形式,或者有没有第三方的控件可以这样做

    阅读更多
  • 这个错误不是编译器的错误,而是IntelliSense的错误。
    这种情况,可以不用太担心。

    如果你使用MSVC编译应用程序,那么最好安装Qt Visual Studio Addon,使用这个插件同步开发Qt应用程序。
    不过一个小小的建议,就是Qt Creator写Qt程序非常直观,不需要在Visual Studio中那么麻烦,而且Qt Creator是强制安装的,基本上你安装了Qt 5.12,就可以在安装的目录中找到它。QAxContainer是Qt的模块activeQt中的,需要在pro文件中写QT += axcontainer,才会找到这个类。

    阅读更多
  • C

    VS2017 Qt5.12
    新建一个空的QWidget对话框,编译执行
    可以成功生成并执行,但是错误列表里显示

    傲游截图20190217212931.png

    exe文件能够成功生成。

    另外的问题:我在vs2017编译环境中使用qt,需要用到 QAxContainer,我看帮助文档里说要在.pro中加入CONFIG+=qaxcontainer,但是vs2017创建的程序中没有.pro这个文件,那这句话应该加在哪里呢?

    还有我想建一个有浏览器控件的对话框程序,如果想在5.12版本中加入QtWebKit应该如何使用

    阅读更多

关注我们

微博
QQ群











召唤伊斯特瓦尔