веб-сервер https

Ответить
ya
^-^
Сообщения: 2336
Зарегистрирован: 16 дек 2021, 19:56

веб-сервер https

Сообщение ya »

Код: Выделить всё

sudo apt update
sudo apt install libboost-all-dev libssl-dev autobahn-cpp-dev libwebsocketpp-dev libasio-dev libboost-dev libboost-system-dev libboost-thread-dev 

Код: Выделить всё

sudo apt-get install build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev libboost-all-dev

Код: Выделить всё

ln -s /home/gt/Downloads/boost_1_85_0 /usr/local/include/boost
web-https.cpp

Код: Выделить всё

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <string>

namespace beast = boost::beast;           
namespace http = beast::http;             
namespace net = boost::asio;              
using tcp = boost::asio::ip::tcp;         
using ssl_stream = beast::ssl_stream<beast::tcp_stream>;

// Этот класс будет обрабатывать запросы
class http_session : public std::enable_shared_from_this<http_session> {
    ssl_stream stream_;
    beast::flat_buffer buffer_;
    
public:
    http_session(tcp::socket socket, ssl::context& ctx)
        : stream_(std::move(socket), ctx) {
    }

    void run() {
        do_handshake();
    }

private:
    void do_handshake() {
        // Установим SSL/TLS соединение
        stream_.async_handshake(ssl::stream_base::server,
            beast::bind_front_handler(&http_session::on_handshake, shared_from_this()));
    }

    void on_handshake(beast::error_code ec) {
        if(ec) {
            std::cerr << "Handshake error: " << ec.message() << std::endl;
            return;
        }
        do_read();
    }

    void do_read() {
        // Читаем запрос
        http::async_read(stream_, buffer_, request_,
            beast::bind_front_handler(&http_session::on_read, shared_from_this()));
    }

    void on_read(beast::error_code ec, std::size_t bytes_transferred) {
        boost::ignore_unused(bytes_transferred);
        
        if(ec) {
            std::cerr << "Read error: " << ec.message() << std::endl;
            return;
        }

        // Отправка ответа
        std::string response_body = "Hello, SSL world!";
        http::response<http::string_body> response{http::status::ok, request_.version()};
        response.set(http::field::server, "Beast");
        response.set(http::field::content_type, "text/plain");
        response.content_length(response_body.size());
        response.body() = std::move(response_body);
        response.prepare_payload();

        // Отправка ответа
        http::async_write(stream_, response,
            beast::bind_front_handler(&http_session::on_write, shared_from_this(), response.need_eof()));
    }

    void on_write(bool close, beast::error_code ec, std::size_t bytes_transferred) {
        boost::ignore_unused(bytes_transferred);
        
        if(ec) {
            std::cerr << "Write error: " << ec.message() << std::endl;
            return;
        }

        if(close) {
            return; // Закрытие соединения
        }

        do_read(); // Чтение следующего запроса
    }

    http::request<http::string_body> request_;
};

// Серверный класс
class http_server {
public:
    http_server(net::io_context& ioc, ssl::context& ctx, tcp::endpoint endpoint)
        : acceptor_(ioc, endpoint) {
        do_accept(ctx);
    }

private:
    tcp::acceptor acceptor_;

    void do_accept(ssl::context& ctx) {
        acceptor_.async_accept(
            [this, &ctx](beast::error_code ec, tcp::socket socket) {
                if (!ec) {
                    std::make_shared<http_session>(std::move(socket), ctx)->run();
                }
                do_accept(ctx);
            });
    }
};

int main(int argc, char* argv[]) {
    try {
        asio::io_context io_context;
        // Настройка контекста SSL
        ssl::context ctx(ssl::context::sslv23);
        ctx.set_options(ssl::context::default_workarounds | ssl::context::no_sslv2 | ssl::context::no_sslv3);

        // Укажите путь к вашему SSL сертификату и закрытому ключу
        ctx.use_certificate_chain_file("server.crt");
        ctx.use_private_key_file("server.key", ssl::context::pem);

        net::io_context ioc;

        // Создаем серверный экземпляр
        tcp::endpoint endpoint{tcp::v4(), 8080};
        http_server server(ioc, ctx, endpoint);

        ioc.run();
    } catch (std::exception& e) {
        std::cerr << "Ошибка: " << e.what() << std::endl;
    }
}
SSL контекст: Мы создаем SSL контекст и указываем путь к вашим сертификату и закрытому ключу (файлы server.crt и server.key).
Сессия: Каждая сессия использует ssl_stream, чтобы обеспечить SSL/TLS защиту.
Асинхронные операции: Используются асинхронные функции async_handshake, async_read, и async_write для обработки сетевых операций не блокируя основной поток.
Обработка запросов: После получения запроса сервер формирует простой текстовый ответ.

Компиляция:

Код: Выделить всё

g++ -std=c++11 -o web-https web-https.cpp -lboost_system -lpthread -lssl -lcrypto
Копмиляция, если буст установлен с сырцов на https://boost.org

Код: Выделить всё

g++ -std=c++11 -o web-https web-https.cpp -I/home/gt/Downloads/boost_1_85_0 -L/home/gt/Downloads/boost_1_85_0/stage/lib -lboost_system -lpthread -lssl -lcrypto
Самоподписанный сертификат:

Код: Выделить всё

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
или

Код: Выделить всё

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"
Самоподписанный сертификат второй вариант:

Код: Выделить всё

# Создание ключа
openssl genrsa -out mykey.key 2048

# Создание запроса на сертификат
openssl req -new -key mykey.key -out myrequest.csr

# Создание самоподписанного сертификата
openssl x509 -req -days 365 -in myrequest.csr -signkey mykey.key -out mycert.crt

Отладчик gdb

Код: Выделить всё

gdb ./your_program
run
# После сбоев
bt  # Покажет стек вызовов
Покажет утечки памяти

Код: Выделить всё

valgrind ./your_program
ya
^-^
Сообщения: 2336
Зарегистрирован: 16 дек 2021, 19:56

Re: веб-сервер https

Сообщение ya »

v-0.0.1

Код: Выделить всё

#include <openssl/ssl.h>
#include <openssl/err.h>
// ... [other includes and existing code]

// Utility function to initialize OpenSSL
void initOpenSSL() {
    SSL_load_error_strings();   
    OpenSSL_add_ssl_algorithms();
}

// Utility function to create SSL context
SSL_CTX* createContext() {
    SSL_CTX* ctx = SSL_CTX_new(TLS_server_method());
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    return ctx;
}

// Utility function to configure context
void configureContext(SSL_CTX* ctx) {
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);

    // Load the certificate and private key
    if (SSL_CTX_use_certificate_file(ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
}

int main() {
    initOpenSSL(); // Initialize OpenSSL

    SSL_CTX* ctx = createContext(); // Create SSL context
    configureContext(ctx); // Configure the SSL context

    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket failed");
        exit(EXIT_FAILURE);
    }
    
    // ... [existing socket setup code]

    // Create a new SSL object
    SSL* ssl;

    std::cout << "Server is listening on port " << PORT << std::endl;

    Model model;
    View view;
    Controller controller(model, view);

    while (true) {
        if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
            perror("Accept failed");
            exit(EXIT_FAILURE);
        }

        // Create a new SSL object for the connection
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, new_socket); // Bind the SSL object to the socket

        // Accept SSL connection
        if (SSL_accept(ssl) <= 0) {
            ERR_print_errors_fp(stderr);
        } else {
            char buffer[BUFFER_SIZE] = {0};
            SSL_read(ssl, buffer, BUFFER_SIZE); // Read from the SSL socket
            std::string request(buffer);
            std::cout << "Received request:\n" << request << std::endl;
            
            std::string response = controller.handleRequest(request);
            SSL_write(ssl, response.c_str(), response.size()); // Write the response
        }

        SSL_shutdown(ssl); // Shutdown SSL connection
        SSL_free(ssl); // Free the SSL object
        close(new_socket); // Close the client socket
    }

    SSL_CTX_free(ctx); // Free SSL context
    EVP_cleanup(); // Cleanup OpenSSL
    return 0;
}
Ответить