实现思路概述
配置项加密传输的核心是构建双重防护机制,第一层利用TLS协议建立安全的传输通道,防止传输过程中的中间人窃听,第二层在应用层对配置项内容再做一次加密,即使TLS通道被突破,攻击者也无法直接获取明文配置。整体流程分为通道建立、应用层加密、数据发送、接收解密四个步骤。
TLS通道搭建
在C++中可以使用OpenSSL库来实现TLS客户端和服务端的搭建,首先需要在项目中引入OpenSSL依赖,然后分别实现服务端和客户端的TLS上下文初始化、握手逻辑。
服务端TLS初始化示例
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
// 初始化OpenSSL库
void init_openssl() {
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
// 清理OpenSSL资源
void cleanup_openssl() {
EVP_cleanup();
}
// 创建服务端SSL上下文
SSL_CTX* create_server_ssl_ctx(const char* cert_path, const char* key_path) {
// 创建TLS1.2及以上的上下文
SSL_CTX* ctx = SSL_CTX_new(TLS_server_method());
if (!ctx) {
std::cerr << "创建SSL上下文失败" << std::endl;
return nullptr;
}
// 加载服务端证书
if (SSL_CTX_use_certificate_file(ctx, cert_path, SSL_FILETYPE_PEM) <= 0) {
std::cerr << "加载证书失败" << std::endl;
SSL_CTX_free(ctx);
return nullptr;
}
// 加载服务端私钥
if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) <= 0) {
std::cerr << "加载私钥失败" << std::endl;
SSL_CTX_free(ctx);
return nullptr;
}
// 验证私钥和证书是否匹配
if (!SSL_CTX_check_private_key(ctx)) {
std::cerr << "私钥和证书不匹配" << std::endl;
SSL_CTX_free(ctx);
return nullptr;
}
return ctx;
}
客户端TLS初始化示例
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
// 创建客户端SSL上下文
SSL_CTX* create_client_ssl_ctx() {
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
if (!ctx) {
std::cerr << "创建客户端SSL上下文失败" << std::endl;
return nullptr;
}
// 不验证服务端证书,实际生产环境需要加载可信CA证书
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr);
return ctx;
}
// 建立TLS连接
SSL* connect_tls(SSL_CTX* ctx, int sockfd) {
SSL* ssl = SSL_new(ctx);
if (!ssl) {
std::cerr << "创建SSL对象失败" << std::endl;
return nullptr;
}
// 绑定socket到SSL对象
SSL_set_fd(ssl, sockfd);
// 执行TLS握手
if (SSL_connect(ssl) <= 0) {
std::cerr << "TLS握手失败" << std::endl;
SSL_free(ssl);
return nullptr;
}
return ssl;
}
应用层加密实现
应用层加密可以选择轻量的对称加密算法,比如AES-256-CBC,对配置项的明文内容做加密后再放入TLS通道传输。这里使用OpenSSL的EVP接口实现AES加密和解密。
AES加密工具实现
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <cstring>
#include <iostream>
#include <vector>
// AES-256-CBC加密函数,返回加密后的数据和IV
std::pair<std::vector<unsigned char>, std::vector<unsigned char>> aes_encrypt(const std::string& plaintext, const unsigned char* key) {
// 生成16字节的随机IV
std::vector<unsigned char> iv(16);
if (RAND_bytes(iv.data(), iv.size()) != 1) {
std::cerr << "生成随机IV失败" << std::endl;
return {};
}
// 初始化加密上下文
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
std::cerr << "创建加密上下文失败" << std::endl;
return {};
}
// 初始化加密操作
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv.data()) != 1) {
std::cerr << "初始化加密失败" << std::endl;
EVP_CIPHER_CTX_free(ctx);
return {};
}
// 加密明文
std::vector<unsigned char> ciphertext(plaintext.size() + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
int len = 0;
int ciphertext_len = 0;
if (EVP_EncryptUpdate(ctx, ciphertext.data(), &len, (unsigned char*)plaintext.data(), plaintext.size()) != 1) {
std::cerr << "加密数据失败" << std::endl;
EVP_CIPHER_CTX_free(ctx);
return {};
}
ciphertext_len = len;
// 处理最后一块数据
if (EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len) != 1) {
std::cerr << "加密收尾失败" << std::endl;
EVP_CIPHER_CTX_free(ctx);
return {};
}
ciphertext_len += len;
ciphertext.resize(ciphertext_len);
EVP_CIPHER_CTX_free(ctx);
return {ciphertext, iv};
}
// AES-256-CBC解密函数,传入密文、IV和密钥返回明文
std::string aes_decrypt(const std::vector<unsigned char>& ciphertext, const std::vector<unsigned char>& iv, const unsigned char* key) {
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
std::cerr << "创建解密上下文失败" << std::endl;
return "";
}
// 初始化解密操作
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv.data()) != 1) {
std::cerr << "初始化解密失败" << std::endl;
EVP_CIPHER_CTX_free(ctx);
return "";
}
// 解密密文
std::vector<unsigned char> plaintext(ciphertext.size());
int len = 0;
int plaintext_len = 0;
if (EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size()) != 1) {
std::cerr << "解密数据失败" << std::endl;
EVP_CIPHER_CTX_free(ctx);
return "";
}
plaintext_len = len;
// 处理最后一块数据
if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) {
std::cerr << "解密收尾失败" << std::endl;
EVP_CIPHER_CTX_free(ctx);
return "";
}
plaintext_len += len;
plaintext.resize(plaintext_len);
EVP_CIPHER_CTX_free(ctx);
return std::string(plaintext.begin(), plaintext.end());
}
完整传输流程示例
下面是客户端加密配置项并发送,服务端接收解密的完整流程示例,假设双方已经提前协商好32字节的AES密钥。
客户端发送逻辑
#include <string>
#include <vector>
#include <iostream>
// 假设已经建立好TLS连接,ssl是已完成的SSL对象
void send_config(SSL* ssl, const std::string& config_content, const unsigned char* aes_key) {
// 应用层加密配置项
auto [ciphertext, iv] = aes_encrypt(config_content, aes_key);
if (ciphertext.empty()) {
std::cerr << "配置项加密失败" << std::endl;
return;
}
// 构造传输数据格式:IV长度(4字节) + IV + 密文长度(4字节) + 密文
unsigned int iv_len = iv.size();
unsigned int cipher_len = ciphertext.size();
// 发送IV长度
SSL_write(ssl, &iv_len, sizeof(iv_len));
// 发送IV
SSL_write(ssl, iv.data(), iv_len);
// 发送密文长度
SSL_write(ssl, &cipher_len, sizeof(cipher_len));
// 发送密文
SSL_write(ssl, ciphertext.data(), cipher_len);
std::cout << "配置项发送完成" << std::endl;
}
服务端接收逻辑
#include <string>
#include <vector>
#include <iostream>
// 假设已经建立好TLS连接,ssl是已完成的SSL对象
std::string recv_config(SSL* ssl, const unsigned char* aes_key) {
unsigned int iv_len = 0;
unsigned int cipher_len = 0;
// 接收IV长度
SSL_read(ssl, &iv_len, sizeof(iv_len));
// 接收IV
std::vector<unsigned char> iv(iv_len);
SSL_read(ssl, iv.data(), iv_len);
// 接收密文长度
SSL_read(ssl, &cipher_len, sizeof(cipher_len));
// 接收密文
std::vector<unsigned char> ciphertext(cipher_len);
SSL_read(ssl, ciphertext.data(), cipher_len);
// 应用层解密
std::string config_content = aes_decrypt(ciphertext, iv, aes_key);
if (config_content.empty()) {
std::cerr << "配置项解密失败" << std::endl;
return "";
}
std::cout << "接收并解密配置项成功" << std::endl;
return config_content;
}
注意事项
- AES密钥需要提前通过安全方式在客户端和服务端同步,不要通过本次传输通道发送
- 生产环境中TLS服务端需要配置可信证书,客户端需要验证服务端证书合法性,避免中间人攻击
- 可以根据需求调整加密算法,比如使用AES-256-GCM提升加密效率和安全性
- 传输数据时可以添加校验字段,避免数据被篡改