将C++搭建的简单HTTP服务器升级为 HTTPS 服务器

HTTP 协议是不加密的,容易遭受中间人攻击(MITM)。为了提高安全性,你可以将服务器升级为 HTTPS 服务器,使用 SSL/TLS 加密流量。下面是如何将以下链接文章中的 HTTP 服务器修改为 HTTPS 服务器的步骤:

ps:使用C++构建一个简单的HTTP服务器,处理请求和响应_html请求 c++服务端-CSDN博客

使用 OpenSSL 生成自签名证书

首先,你需要生成自签名证书。以下是一个简单的命令:

复制代码
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

这个命令会生成一个有效期为 365 天的自签名证书 (cert.pem) 和私钥文件 (key.pem)。

修改服务器代码以支持 HTTPS

接下来,修改你的服务器代码以使用 QSslSocketQSslConfiguration 来支持 HTTPS。

复制代码
#include <QCoreApplication>
#include <QTcpServer>
#include <QSslSocket>
#include <QDebug>
#include <QTextStream>
#include <QSslConfiguration>
#include <QSslKey>
#include <QSslCertificate>

class HttpsServer : public QTcpServer {
    Q_OBJECT

public:
    HttpsServer(QObject *parent = nullptr) : QTcpServer(parent) {
        // 加载证书和私钥
        QFile certFile("cert.pem");
        QFile keyFile("key.pem");
        if (!certFile.open(QIODevice::ReadOnly) || !keyFile.open(QIODevice::ReadOnly)) {
            qCritical() << "Failed to open certificate or key file.";
            return;
        }
        QSslCertificate certificate(&certFile, QSsl::Pem);
        QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem);
        certFile.close();
        keyFile.close();

        sslConfig.setLocalCertificate(certificate);
        sslConfig.setPrivateKey(privateKey);
        sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // 这里设置为 VerifyNone 仅用于测试
    }

protected:
    void incomingConnection(qintptr socketDescriptor) override {
        QSslSocket *socket = new QSslSocket(this);
        if (socket->setSocketDescriptor(socketDescriptor)) {
            socket->setSslConfiguration(sslConfig);
            socket->startServerEncryption();
            connect(socket, &QSslSocket::encrypted, this, &HttpsServer::handleConnection);
            connect(socket, &QSslSocket::disconnected, socket, &QSslSocket::deleteLater);
        } else {
            qWarning() << "Failed to set socket descriptor.";
            delete socket;
        }
    }

private slots:
    void handleConnection() {
        QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
        if (!socket) return;

        connect(socket, &QSslSocket::readyRead, this, &HttpsServer::handleRequest);
    }

    void handleRequest() {
        QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
        if (!socket) return;

        QTextStream in(socket);
        QString request = in.readAll();

        qDebug() << "Received encrypted request:\n" << request;

        // 构建 HTTP 响应
        QString response = "HTTP/1.1 200 OK\r\n";
        response += "Content-Type: text/html; charset=UTF-8\r\n";
        response += "\r\n";
        response += "<html><body><h1>Hello, World!</h1></body></html>";

        // 发送响应
        QTextStream out(socket);
        out << response;
        socket->flush();
        socket->close();
    }

private:
    QSslConfiguration sslConfig;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    HttpsServer server;
    if (!server.listen(QHostAddress::Any, 443)) { // 使用 443 端口
        qCritical() << "Unable to start the server:" << server.errorString();
        return 1;
    }

    qDebug() << "Listening on port 443...";

    return a.exec();
}

#include "main.moc"

关键修改点

  1. 使用 QSslSocket 代替 QTcpSocket

    • QSslSocketQTcpSocket 的扩展,支持加密通信。
    • incomingConnection 方法中,使用 QSslSocket 设置 Socket 描述符,并启动 SSL 加密。
  2. 加载证书和私钥

    • 在构造函数中加载证书 (cert.pem) 和私钥 (key.pem) 文件,并设置 SSL 配置。
    • sslConfig.setLocalCertificatesslConfig.setPrivateKey 用于设置证书和私钥。
  3. 修改监听端口

    • 将监听端口从 80 修改为 443,这是 HTTPS 的标准端口。
  4. 处理加密连接

    • incomingConnection 中,调用 socket->startServerEncryption() 启动加密。
    • 连接 QSslSocket::encrypted 信号到 handleConnection 槽,确保数据在加密状态下读取。

运行服务器

确保你的证书 (cert.pem) 和私钥文件 (key.pem) 在可执行文件的同一目录下,然后编译并运行服务器。服务器现在将监听 443 端口,并使用 SSL/TLS 加密流量,从而提高安全性,防止中间人攻击。

相关推荐
tao35566713 分钟前
VS Code登录codex,报错(os error 10013)
java·服务器·前端
陈让然16 分钟前
VS Code新版本无法连接WSL ubuntu18.04
linux·运维·ubuntu
lpfasd12319 分钟前
宝塔面板使用流程及注意事项
运维
小杰帅气20 分钟前
神秘的环境变量和进程地址空间
linux·运维·服务器
胖咕噜的稞达鸭23 分钟前
进程间的通信(1)(理解管道特性,匿名命名管道,进程池,systeam V共享内存是什么及优势)重点理解代码!
linux·运维·服务器·数据库
电气铺二表姐1377441661523 分钟前
超市冷柜专区电能计量方案:高能耗设备独立监测与优化
运维·物联网·能源
小北方城市网36 分钟前
微服务接口设计实战指南:高可用、易维护的接口设计原则与规范
java·大数据·运维·python·微服务·fastapi·数据库架构
可爱又迷人的反派角色“yang”37 分钟前
k8s(五)
linux·运维·docker·云原生·容器·kubernetes
爱吃生蚝的于勒41 分钟前
【Linux】进程间通信之匿名管道
linux·运维·服务器·c语言·数据结构·c++·vim
SHolmes18541 小时前
Python all函数 判断是否同时满足多个条件
java·服务器·python