配置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年还会出现,我们层经做过静态编译带聊天,曾经实现了,现在由于架构更改了,可能问题又是一大堆吧。


Log in to reply
 

走马观花

最近的回复

  • @qyvlik 这个例子可否提供学习一下?

    read more
  • 113.jpg
    1、什么是lambda表达式,什么是闭包?
    lambda表达式即lambda函数,也就是匿名函数。

    lambda表达式在C++中包含了
    []表示捕获
    ()是函数的参数,需要指定类型
    ->type是返回的类型,可以省略,如果编译器无法推出类型的话可以强制编写
    {}是函数体。

    lambda可以被声明为mutable的,作用是将捕获的内容进行改变。
    闭包是函数的定义以及定义函数时提供的环境,总称为闭包。lambda函数也是一种闭包。
    lambda本身是匿名函数,而捕获语句则是提供了定义函数时提供的环境。

    2、什么是右值引用?
    右值引用相对与左值引用而言的。左值即=运算符左边的变量,右值是=运算符右边的常量或变量。由此可以看出,
    右值引用指的是对常量或变量的引用。它的用途包含了移动语义和完美转发。
    移动语义就是弥补了C++历史在处理变量传递时丢失的一种语义。它和值传递、引用传递一样,是变量传递的方式之一。
    如果没有移动语义,为了将一个类的实例传递给另外一个实例,就需要额外地进行构造、赋值、销毁的操作。
    对于一些比较复杂的变量,的确是非常耗时并且消耗大的操作。(浪费指令时间、浪费内存)

    对于这样的函数返回:
    vector<string> str_split(const string& s) {
    vector<string> v;
    // ...
    return v; // v是左值,但优先移动,不支持移动时仍可复制。
    }

    标准要求先调用移动构造函数,如果不符合那么再调用拷贝构造函数。所以可以轻松地写出这种写法而不必担心效率问题。
    同时,现代编译器都会对返回值进行优化,成为RVO以及NRVO。所以不用太担心会多调用构造析构函数。

    对于完美转发,C++对于引用的转发有规则。传统的C++是无法对引用进行再引用的。但是现代的C++放宽了它的使用范围。
    只有右引用右值的时候,才会产生右引用。这也称为引用折叠。

    3、auto关键字的作用是什么?
    auto关键字为的是能够让编译器自动推导类型。自C++98之后,编译器对类型的推导变得越来越智能了。
    而我们在编写复杂代码的时候,冗长的类型不仅容易出错,有时也不容易人工推导出类型。
    因此auto可以简化我们的任务量,让类型的推导交给编译器完成。
    除了auto外,我们还可以使用decltype()来让编译器推导类型。

    read more
  • 我感觉比起《Physically Based Rendering Technique》,还是《Ray Tracing in a Weekend》更容易上手,因为慢慢地能够做出一个渲染效果,这个是有成就感的。🎓

    read more
  • G

    北京名律免费法律咨询,解决您的法律困扰,如果您眼下没有遇到法律上的问题,也可以留一位大律师的联系方式以备不时之需!ccfd91efc3a6b2ed0e79054d2248eed.jpg bf6015b383483f1fe83cdcfd130fc6b.jpg 2f347879129add1096bf3424edbe517.jpg

    read more

关注我们

微博
QQ群