QT实现Webdav的HTTPS通信

闲来没事,再来一篇博文,讲讲我最近做的QT实现的Webdav通信HTTPS实现。

HTTP太不安全了,抓包随便就可以拿到报文,但是Webdav有不能通过QT自带的authenticationRequired进行用户名和密码的验证,只好自己拼接报文头,
本项目就是介绍如何用HTTPS进行Webdav通信。
authenticationRequired就是相当于我们访问一个ftp,ftp需要用户输入用户名和密码,authenticationRequired就是让用户输入
如果url是http的话,authenticationRequired是有效的,可以直接用,但是HTTPS就不行,直接就是报错RemoteHostClosedError,所以自己实现了填写HTTPS头部
    QString concatenated = QString("app1") + ":" + QString("ssssss");
    QByteArray data = concatenated.toLocal8Bit().toBase64();
    QString headerData = "Basic " + data;
    gRequest.setRawHeader("Authorization", headerData.toLocal8Bit());
这样就行了,抓包看到的内容全部是加密的。安全了。


HTTP太不安全了,抓包随便就可以拿到报文。不信你看下图:

这个是我用http实现的webdav的访问抓包图:

QT实现Webdav的HTTPS通信_第1张图片


首先是TCP的三次握手,接着客户端向服务器端发送了请求,明文的请求啊。后面从服务器端返回来的数据也是明文的。好的,直接上代码吧。

main.cpp

#include "mainwindow.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    webdavthreadclient = new webdavthread();
    webdavthreadclient->DoSetup(cthread);
    webdavthreadclient->moveToThread(&cthread);

    connect(this, SIGNAL(startwebdav()), webdavthreadclient, SLOT(webdav()));

    if(!cthread.isRunning()){
        cthread.start();
    }else{
        emit startwebdav();
    }
}

MainWindow::~MainWindow()
{

    if(cthread.isRunning()){
        cthread.quit();
        cthread.wait();
    }

    delete ui;
}
webdavthread.cpp

#include "webdavthread.h"

#include 
#include 
#include 


webdavthread::webdavthread(QObject *parent) : QObject(parent)
{

}


void webdavthread::DoSetup(QThread &cThread){
    connect(&cThread,SIGNAL(started()),this,SLOT(webdav()));

}
void webdavthread::webdav(){

    QNetworkAccessManager *gManager = new QNetworkAccessManager;
    // Read the SSL certificate
    QFile file("D:/QT_workspace/test01/certificate/ssl.crt");

    //QFile file("D:/QT_workspace/QThreadWebdav/cert/localhost.pem");
    //QFile file("D:/QT_workspace/QThreadWebdav/cert/localhost.crt");
    file.open(QIODevice::ReadOnly);
    QByteArray bytes = file.readAll();

    // Create a certificate object
    //QSslCertificate certificate(bytes);
    // Add this certificate to all SSL connections
    //QSslSocket::addDefaultCaCertificate(certificate);
    QNetworkRequest gRequest;
    //QSslConfiguration config = gRequest.sslConfiguration();
    QSslConfiguration config = QSslConfiguration::defaultConfiguration();

    //config.setCaCertificates(certificate);
    //config.setLocalCertificate(certificate);
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1_0OrLater);

    //config.setLocalCertificate(certificate);
    gRequest.setSslConfiguration(config);

    QString url_s = "https://localhost/webdav.php";
    QUrl url(url_s);

    gRequest.setUrl(url);
    gRequest.setRawHeader("Connection", "keep-alive");

    QString concatenated = QString("username") + ":" + QString("password");
    QByteArray data = concatenated.toLocal8Bit().toBase64();
    QString headerData = "Basic " + data;
    gRequest.setRawHeader("Authorization", headerData.toLocal8Bit());//这里是webdav的用户名和密码验证

    gRequest.setRawHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,*\/*;q=0.8");

    gRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");

    connect(gManager, SIGNAL(finished(QNetworkReply*)),this, SLOT(sendReplyFinished(QNetworkReply*)));

    connect(gManager, SIGNAL(sslErrors(QNetworkReply*,QList)), this, SLOT(sslErrors(QNetworkReply*,QList)));

    connect(gManager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(provideAuthenication(QNetworkReply*,QAuthenticator*)));

    webdavthread::PropNames query;
    QStringList props;

    props << "getlastmodified";
    props << "getcontentlength";
    props << "resourcetype";
    query["DAV:"] = props;
    QByteArray query1;

    query1 = "";
    query1 += "";
    query1 += "";
    foreach (QString ns, query.keys())
    {
        foreach (const QString key, query[ns])
            if (ns == "DAV:")
                query1 += "";
            else
                query1 += "<" + key + " xmlns=\"" + ns + "\"/>";
    }
    query1 += "";
    query1 += "";

    url.setPath("/");
    //req.setUrl(reqUrl);
    gRequest.setRawHeader("Depth", 1 == 2 ? QString("infinity").toUtf8() : QString::number(1).toUtf8());

    QBuffer* dataIO = new QBuffer;
    dataIO->setData(query1);
    dataIO->open(QIODevice::ReadOnly);
    if(dataIO != 0 && dataIO->size() !=0) {
        gRequest.setHeader(QNetworkRequest::ContentLengthHeader, dataIO->size());

        qDebug()<<"query1 is "<size();

        //gRequest.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml; charset=utf-8");
    }
   // QString strdata("PROPFIND");
    //QByteArray PROPData = QByteArray("PROPFIND", 9);
    m_reply = gManager->sendCustomRequest(gRequest, "PROPFIND", dataIO);
    connect(m_reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
    connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
             this, SLOT(slotError(QNetworkReply::NetworkError)));
}




void webdavthread::provideAuthenication(QNetworkReply* reply, QAuthenticator* authenticator){
    qDebug() <<"\n"<<"in provideAuthenication";

    if (reply == m_authenticator_lastReply) {
        reply->abort();
        //emit errorChanged("WebDAV server requires authentication. Check WebDAV share settings!");
        reply->deleteLater();
        reply=0;
    }
    m_authenticator_lastReply = reply;

    QVariantHash opts = authenticator->options();
    QVariant optVar;
    foreach(optVar, opts) {
        qDebug() << "QWebdav::authenticationRequired()  option == " << optVar.toString();
    }
    authenticator->setUser(QString("username"));
    authenticator->setPassword(QString("password"));
    return;

}


void webdavthread::sendReplyFinished(QNetworkReply *re)
{
    qDebug() <<"\n"<<"in sendReplyFinished";
    qDebug() <error()<<"\n";

    if(re->error() == QNetworkReply::NoError){
        QString ans = re->readAll();
        qDebug() <error() == QNetworkReply::RemoteHostClosedError){//RemoteHostClosedError为远处主机关闭了连接时发出的错误信号
        qDebug() <error()<<"\n";
    }
    else if(re->error() == QNetworkReply::AuthenticationRequiredError){

    }

}


void webdavthread::sslErrors(QNetworkReply *reply, const QList &errors)
{

    qDebug() << "sslErrors()   reply->url == " << reply->url().toString(QUrl::RemoveUserInfo);
    qDebug() << "error is " << errors[0];
    QSslCertificate sslcert = errors[0].certificate();
    reply->ignoreSslErrors();

//    if ( ( sslcert.digest(QCryptographicHash::Md5) == m_sslCertDigestMd5 ) &&
//         ( sslcert.digest(QCryptographicHash::Sha1) == m_sslCertDigestSha1) )
//    {
//        // user accepted this SSL certifcate already ==> ignore SSL errors
//        reply->ignoreSslErrors();
//    } else {
//        // user has to check the SSL certificate and has to accept manually
//        emit checkSslCertifcate(errors);
//        reply->abort();
//    }
}

void webdavthread::slotReadyRead(){
    qDebug() << "slotReadyRead";
}
void webdavthread::slotError(QNetworkReply::NetworkError error){
    qDebug() << "slotError error" << error;
}



好的,运行一下,打印的东西
in sendReplyFinished
QNetworkReply::NetworkError(NoError) 

"\n/cnrcloud/files/webdav.php/Wed, 08 Jul 2015 12:54:11 GMTHTTP/1.1 200 OKHTTP/1.1 404 Not Found/cnrcloud/files/webdav.php/2015/Tue, 21 Jul 2015 05:20:27 GMTHTTP/1.1 200 OKHTTP/1.1 404 Not Found/cnrcloud/files/webdav.php/20150723_XJ_05.mp4/Wed, 29 Jul 2015 07:22:10 GMTHTTP/1.1 200 OKHTTP/1.1 404 Not Found/cnrcloud/files/webdav.php/20150723_XJ_06.mp4/Wed, 29 Jul 2015 09:52:47 GMT
成功获取到了服务器端所有的文件。

再用wireshark抓包,可以看到所有内容都加密了。

QT实现Webdav的HTTPS通信_第2张图片

好的,最后要想回到http,只需要把请求的url改成HTTP就行了。


github代码: https://github.com/buptis073114/QThreadWebdav










你可能感兴趣的:(QT实现Webdav的HTTPS通信)