簡體   English   中英

Qt與QSslSocket沒有正確連接

[英]Qt with QSslSocket not connecting properly

我有一個與QTcpSocket一起使用的客戶端 - 服務器應用程序。 現在我想使用加密的SSL連接,因此我嘗試切換到QSslSocket 但我無法建立與服務器的連接。 這是客戶端的代碼:

ConnectionHandler::ConnectionHandler(QString ip, int port, QObject *parent) : QObject(parent) {
//    connect(this->socket, SIGNAL(connected()), this, SLOT(connected()));
    connect(this->socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    connect(this->socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(encryptedReady()));
    connect(this->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(SSLerrorOccured(const QList<QSslError> &)));
    connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
    connect(this->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));

    this->ip = ip;
    this->port = port;
}


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


void ConnectionHandler::socketError(QAbstractSocket::SocketError) {
    qDebug() << this->socket->errorString();
}


void ConnectionHandler::encryptedReady() {
    qDebug() << "READY";

}


void ConnectionHandler::SSLerrorOccured(const QList<QSslError> &) {
    qDebug() << "EEROR";
}


void ConnectionHandler::connectToServer() {
//    this->socket->connectToHost(this->ip, this->port);
    this->socket->connectToHostEncrypted(this->ip, this->port);

    if (!this->socket->waitForConnected(5000)) {
    this->socket->close();
    this->errorMsg = this->socket->errorString();
    }
}


void ConnectionHandler::connected() {
qDebug() << "connected";
    this->connectedHostAddress = this->socket->peerAddress().toString();
    this->connectionEstablished = true;
    this->localIP = this->socket->localAddress().toString();
    this->localPort = this->socket->localPort();
} 

這是服務器的一個:

 ClientHandler::ClientHandler() {
    this->socket->setProtocol(QSsl::SslV3);
    this->socket->setSocketOption(QAbstractSocket::KeepAliveOption, true);
}

void ClientHandler::run() {
    if (!this->fd)
    return;

    connect(this->socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
    connect(this->socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(encryptedReady()));
    connect(this->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrorOccured(const QList<QSslError> &)));
    connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
    connect(this->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));

    if (!this->socket->setSocketDescriptor(this->fd)) {
    emit error(socket->error());
    return;
    } else {
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(ready()));
    this->socket->startServerEncryption();
    }

    this->peerIP = socket->peerAddress().toString();
    QString tmp;
    tmp.append(QString("%1").arg(socket->peerPort()));
    this->peerPort = tmp;

    QHostInfo::lookupHost(this->peerIP, this, SLOT(lookedUp(QHostInfo)));
}


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


void ClientHandler::socketError(QAbstractSocket::SocketError) {
    qDebug() << this->socket->errorString();
}


void ClientHandler::setFileDescriptor(int fd) {
    this->fd = fd;
}

void ClientHandler::ready() {
    qDebug() << "READY";
}

void ClientHandler::sslErrorOccured(const QList<QSslError> &) {
    qDebug() << "EEROR";
}


void ClientHandler::encryptedReady() {
    qDebug() << "READY";

}

我收到的客戶輸出是:

  QAbstractSocket::HostLookupState
  QAbstractSocket::ConnectingState
  QAbstractSocket::ConnectedState
  "The remote host closed the connection"
  QAbstractSocket::ClosingState
  QAbstractSocket::UnconnectedState

並為服務器:

  QAbstractSocket::ConnectedState
  "Error during SSL handshake: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher"
  QAbstractSocket::UnconnectedState

有誰知道如何解決這一問題?

我假設使用非加密套接字一切都很好。 因此,我們只關注QSslSocket細節的QSslSocket 如果需要,我可以分享更大的作品或工作代碼。 關於SSL證書的故事也很多,我將在這里簡要介紹一下。

要開始,讓我們檢查一些外部HTTP SSL服務器上的客戶端,例如:

socket->connectToHostEncrypted("gmail.com", 443);

它應該立即使用默認的SSL協議(沒有任何setProtocol() )。 在信號encrypted()你可以寫HTTP GET頭,在readyRead()上會有回復。

現在嘗試設置socket->setProtocol(QSsl::SslV3); "gmail.com" 預期結果:

sslErrorOccured: ("The host name did not match any of the valid hosts for this certificate")

請注意,它不是error()信號,而是sslErrors()信號通知客戶端可以忽略的證書問題。

因此,為簡單起見,我們使用默認的SSL協議,而不使用setProtocol()

由於客戶端處於工作狀態,我們可以移動到服務器。 您在第一級SSL認證挑戰中被打斷了。 要開始通過服務器初始化SSL連接,您必須至少提供私有加密密鑰和公共證書。 這是你的錯誤:

"Error during SSL handshake: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher"

在完美的情況下,您的證書應由身份驗證機構公司簽署。 在這種情況下,任何具有此類根證書列表的客戶端都可以檢查您的證書是否有效。 但是,該服務已付費,可能需要幾周時間。 我們可以從自簽名證書開始。

您可以找到用於生成證書的各種配方,例如: “如何創建可用於測試目的或內部使用的自簽名SSL證書”

短提取物:

#Step 1: Generate a Private Key
openssl genrsa -des3 -out server.key 1024

#Step 2: Generate a CSR (Certificate Signing Request)
#Common Name (eg, your name or your server's hostname) []:example.com
openssl req -new -key server.key -out server.csr

#Step 3: Remove Passphrase from Key
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key

#Step 4: Generating a Self-Signed Certificate
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

現在有server.keyserver.crt文件。 startServerEncryption()之前,服務器應將這些文件傳遞給QSslSocket

    socket->setPrivateKey("c:/test/ssl/cert/server.key", QSsl::Rsa);
    socket->setLocalCertificate("c:/test/ssl/cert/server.crt");

現在服務器可以啟動SSL連接。 您可以使用瀏覽器進行測試。 通常,瀏覽器會發出連接不受信任的警報。 這是因為證書是自簽名的,它不能防止“中間人”攻擊。 但是,您可以要求瀏覽器繼續該連接。 因此,在服務器端,您將在信號readyRead()上擁有HTTP GET標頭。

嘗試連接Qt客戶端到該服務器。 現在客戶端引發了錯誤:

sslErrorOccured: ("The certificate is self-signed, and untrusted")

服務器在error()說: “遠程主機關閉了連接” 客戶端引發了SSL證書錯誤,但與瀏覽器一樣,我們可以繼續使用該連接。 socket->ignoreSslErrors()放在sslErrors()信號處理程序中:

void Client::sslErrorOccured(const QList<QSslError> & error) {
    qDebug() << "sslErrorOccured:" << error;
    socket->ignoreSslErrors(error);
}

而已。 當然,您的客戶端不應接受來自所有服務器的所有SSL證書錯誤,因為此類錯誤意味着連接不是真正安全且可能被黑客攻擊。 它只是用於測試。 對象QSslError包含證書數據,因此您的客戶端可以只接受來自服務器的一個特定自簽名證書,並忽略所有其他此類錯誤。 您也可以創建自己的“權限根證書”,您可以手動將其寫入系統。 然后,該證書可用於簽署服務器證書。 您的客戶端會認為它是可信連接,因為它可以通過系統根證書對其進行驗證。

請注意,OpenSSL庫也存在一些問題。 在Linux或OS X上,OpenSSL處於默認設置,但對於Windows,應手動安裝。 Windows系統PATH可能已經存在一些OpenSSL編譯,例如CMake有一些有限的OpenSSL庫。 但是,對於Windows,您應該將OpenSSL與應用程序一起部署。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM