物联网设备身份认证与安全通信

作者: zry
标签: 物联网, 安全, 身份认证, TLS, AIDC, 加密通信


目录

  1. 引言
  2. 物联网安全挑战
  3. 身份认证架构设计
  4. 设备注册与证书管理
  5. 双向TLS实现
  6. 令牌认证机制
  7. 密钥轮转与更新
  8. AIDC系统中的实现
  9. 最佳实践
  10. 总结

引言

在AIDC自动气象站数据收集系统中,成千上万的物联网气象设备分布在广阔的地域,通过公共网络与数据中心通信。这些设备采集的温度、湿度、气压等敏感气象数据需要严格保护,防止被窃听、篡改或伪造。

本文将深入探讨AIDC系统中采用的物联网设备身份认证与安全通信方案,包括基于X.509证书的强身份认证、双向TLS加密通信、动态令牌机制等核心技术。


物联网安全挑战

AIDC系统面临的安全威胁

防护措施

攻击面分析

设备端

物理篡改

固件提取

密钥泄露

通信链路

中间人攻击

重放攻击

数据窃听

服务端

DDoS攻击

身份伪造

API滥用

安全启动

安全存储

证书绑定

mTLS

令牌时效

速率限制

安全需求分析

安全属性 威胁场景 防护手段
机密性 数据在传输中被窃听 TLS 1.3加密
完整性 数据被篡改 HMAC签名验证
身份认证 伪造设备接入 X.509证书认证
不可否认性 设备否认发送数据 数字签名
可用性 DDoS攻击 速率限制、熔断

身份认证架构设计

整体架构

uses

manages

queries

authenticates

Device

-string device_id_

-X509Certificate cert_

-PrivateKey private_key_

+authenticate() : AuthResult

+sign_data(data) : Signature

CertificateAuthority

-PrivateKey ca_key_

-X509Certificate ca_cert_

+issue_certificate(csr) : X509Certificate

+revoke_certificate(serial) : void

+verify_certificate(cert) : bool

AuthService

-CertificateAuthority ca_

-TokenIssuer token_issuer_

-DeviceRegistry registry_

+authenticate_device(cert, proof) : AuthToken

+refresh_token(token) : AuthToken

+validate_token(token) : bool

SecureChannel

-SSLContext ssl_ctx_

-DeviceEndpoint peer_

+establish_tls() : bool

+send_secure(data) : bool

+receive_secure() : Data

DeviceRegistry

-map<string, DeviceInfo> devices_

+register_device(info) : bool

+get_device(id) : DeviceInfo

+update_status(id, status) : void

认证流程时序图

设备注册中心 证书颁发机构 Auth服务 Connect模块 气象设备 设备注册中心 证书颁发机构 Auth服务 Connect模块 气象设备 设备注册阶段(一次性) 日常连接阶段 安全通道建立 生成密钥对 发送CSR(证书签名请求) 转发注册请求 验证设备合法性 返回设备信息 签发设备证书 返回X.509证书 下发证书 安装证书 Client Hello + 证书 验证设备证书 验证证书链 验证通过 查询设备状态 设备正常 认证通过 Server Hello + 证书 验证服务端证书 Finished Finished 加密数据传输 加密响应

设备注册与证书管理

证书层次结构

根CA证书
AIDC Root CA

中间CA
AIDC Device CA

中间CA
AIDC Server CA

设备证书
Station-001

设备证书
Station-002

设备证书
Station-003

服务端证书
Connect服务

服务端证书
ISOS服务

设备注册实现

// device_registration.hpp
#pragma once
#include <openssl/x509.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <string>
#include <vector>
#include <memory>
#include <chrono>

namespace aidc::security {

// 前向声明
class CertificateAuthority;

// 设备注册信息
struct DeviceRegistrationInfo {
    std::string device_id;           // 设备唯一标识
    std::string hardware_id;         // 硬件序列号
    std::string model;               // 设备型号
    std::string firmware_version;    // 固件版本
    std::string location;            // 安装位置
    std::chrono::system_clock::time_point registered_at;
    std::chrono::system_clock::time_point expires_at;
};

// 证书签名请求
struct CertificateSigningRequest {
    std::vector<uint8_t> der_data;   // DER编码的CSR
    std::string device_id;
    std::string common_name;
    
    // 从DER解析CSR信息
    bool parse_from_der(const std::vector<uint8_t>& der);
    
    // 验证CSR签名
    bool verify_signature() const;
};

// 设备证书
class DeviceCertificate {
public:
    explicit DeviceCertificate(X509* cert = nullptr);
    ~DeviceCertificate();
    
    // 禁止拷贝,允许移动
    DeviceCertificate(const DeviceCertificate&) = delete;
    DeviceCertificate& operator=(const DeviceCertificate&) = delete;
    DeviceCertificate(DeviceCertificate&& other) noexcept;
    DeviceCertificate& operator=(DeviceCertificate&& other) noexcept;
    
    // 序列化
    std::vector<uint8_t> to_der() const;
    std::string to_pem() const;
    bool from_der(const std::vector<uint8_t>& der);
    bool from_pem(const std::string& pem);
    
    // 获取证书信息
    std::string get_subject() const;
    std::string get_issuer() const;
    std::string get_serial_number() const;
    std::chrono::system_clock::time_point get_not_before() const;
    std::chrono::system_clock::time_point get_not_after() const;
    
    // 验证证书
    bool verify_signature(EVP_PKEY* issuer_key) const;
    bool is_expired() const;
    bool is_valid_now() const;
    
    // 获取公钥
    EVP_PKEY* get_public_key() const;
    
    // 内部X509指针访问
    X509* native_handle() const { return cert_; }

private:
    X509* cert_;
};

// 设备注册管理器
class DeviceRegistrationManager {
public:
    explicit DeviceRegistrationManager(
        std::shared_ptr<CertificateAuthority> ca);
    
    // 处理设备注册请求
    struct RegistrationResult {
        bool success;
        std::string error_message;
        DeviceCertificate certificate;
        std::string issued_token;
    };
    
    RegistrationResult register_device(
        const CertificateSigningRequest& csr,
        const DeviceRegistrationInfo& info);
    
    // 批量注册(用于预置设备)
    std::vector<RegistrationResult> batch_register(
        const std::vector<std::pair<CertificateSigningRequest, 
                                    DeviceRegistrationInfo>>& requests);
    
    // 吊销设备证书
    bool revoke_device(const std::string& device_id);
    
    // 更新设备证书
    RegistrationResult renew_certificate(
        const std::string& device_id,
        const CertificateSigningRequest& csr);
    
    // 查询设备状态
    struct DeviceStatus {
        std::string device_id;
        bool is_active;
        bool is_revoked;
        std::chrono::system_clock::time_point cert_expires;
        std::chrono::system_clock::time_point last_seen;
    };
    
    std::optional<DeviceStatus> query_device_status(
        const std::string& device_id) const;

private:
    std::shared_ptr<CertificateAuthority> ca_;
    
    // 设备注册存储
    class DeviceRegistryImpl;
    std::unique_ptr<DeviceRegistryImpl> registry_;
    
    // 生成设备证书
    DeviceCertificate issue_certificate(
        const CertificateSigningRequest& csr,
        const DeviceRegistrationInfo& info);
    
    // 验证设备合法性
    bool validate_device_identity(const DeviceRegistrationInfo& info) const;
};

} // namespace aidc::security

证书颁发机构实现

// certificate_authority.cpp
#include "certificate_authority.hpp"
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <spdlog/spdlog.h>
#include <fstream>

namespace aidc::security {

// 生成序列号
static std::vector<uint8_t> generate_serial_number() {
    std::vector<uint8_t> serial(20);
    if (RAND_bytes(serial.data(), serial.size()) != 1) {
        throw std::runtime_error("Failed to generate random serial number");
    }
    // 确保正数
    serial[0] &= 0x7F;
    return serial;
}

// 设置证书有效期
static void set_certificate_validity(X509* cert, 
                                     int days_valid,
                                     std::chrono::system_clock::time_point not_before = 
                                         std::chrono::system_clock::now()) {
    ASN1_TIME* not_before_asn1 = ASN1_TIME_new();
    ASN1_TIME* not_after_asn1 = ASN1_TIME_new();
    
    auto not_before_t = std::chrono::system_clock::to_time_t(not_before);
    auto not_after = not_before + std::chrono::hours(24 * days_valid);
    auto not_after_t = std::chrono::system_clock::to_time_t(not_after);
    
    ASN1_TIME_set(not_before_asn1, not_before_t);
    ASN1_TIME_set(not_after_asn1, not_after_t);
    
    X509_set_notBefore(cert, not_before_asn1);
    X509_set_notAfter(cert, not_after_asn1);
    
    ASN1_TIME_free(not_before_asn1);
    ASN1_TIME_free(not_after_asn1);
}

class CertificateAuthority::Impl {
public:
    Impl(const std::string& ca_cert_path, 
         const std::string& ca_key_path,
         const std::string& passphrase = "") {
        // 加载CA证书
        FILE* cert_file = fopen(ca_cert_path.c_str(), "r");
        if (!cert_file) {
            throw std::runtime_error("Failed to open CA certificate file");
        }
        ca_cert_.reset(PEM_read_X509(cert_file, nullptr, nullptr, nullptr));
        fclose(cert_file);
        
        if (!ca_cert_) {
            throw std::runtime_error("Failed to load CA certificate");
        }
        
        // 加载CA私钥
        FILE* key_file = fopen(ca_key_path.c_str(), "r");
        if (!key_file) {
            throw std::runtime_error("Failed to open CA key file");
        }
        
        auto password_cb = [](char* buf, int size, int rwflag, void* userdata) -> int {
            const std::string* pass = static_cast<const std::string*>(userdata);
            if (pass->empty()) return 0;
            int len = std::min(size, static_cast<int>(pass->size()));
            memcpy(buf, pass->data(), len);
            return len;
        };
        
        ca_key_.reset(PEM_read_PrivateKey(key_file, nullptr, 
                                          password_cb, 
                                          const_cast<void*>(
                                              static_cast<const void*>(&passphrase))));
        fclose(key_file);
        
        if (!ca_key_) {
            throw std::runtime_error("Failed to load CA private key");
        }
        
        spdlog::info("CertificateAuthority initialized successfully");
    }
    
    DeviceCertificate issue_certificate(const CertificateSigningRequest& csr,
                                       int validity_days = 365) {
        // 解析CSR
        const uint8_t* data = csr.der_data.data();
        std::unique_ptr<X509_REQ, decltype(&X509_REQ_free)> req(
            d2i_X509_REQ(nullptr, &data, csr.der_data.size()),
            X509_REQ_free);
        
        if (!req) {
            throw std::runtime_error("Failed to parse CSR");
        }
        
        // 验证CSR签名
        EVP_PKEY* req_pubkey = X509_REQ_get_pubkey(req.get());
        if (X509_REQ_verify(req.get(), req_pubkey) != 1) {
            EVP_PKEY_free(req_pubkey);
            throw std::runtime_error("CSR signature verification failed");
        }
        
        // 创建新证书
        X509* cert = X509_new();
        if (!cert) {
            EVP_PKEY_free(req_pubkey);
            throw std::runtime_error("Failed to create certificate");
        }
        
        // 设置版本号(v3)
        X509_set_version(cert, 2);
        
        // 设置序列号
        auto serial = generate_serial_number();
        BIGNUM* serial_bn = BN_bin2bn(serial.data(), serial.size(), nullptr);
        ASN1_INTEGER* serial_asn1 = BN_to_ASN1_INTEGER(serial_bn, nullptr);
        X509_set_serialNumber(cert, serial_asn1);
        BN_free(serial_bn);
        ASN1_INTEGER_free(serial_asn1);
        
        // 设置签发者
        X509_set_issuer_name(cert, X509_get_subject_name(ca_cert_.get()));
        
        // 设置主体(使用CSR中的信息)
        X509_set_subject_name(cert, X509_REQ_get_subject_name(req.get()));
        
        // 设置有效期
        set_certificate_validity(cert, validity_days);
        
        // 设置公钥
        X509_set_pubkey(cert, req_pubkey);
        EVP_PKEY_free(req_pubkey);
        
        // 添加扩展
        add_extensions(cert, csr);
        
        // 签名证书
        if (X509_sign(cert, ca_key_.get(), EVP_sha256()) <= 0) {
            X509_free(cert);
            throw std::runtime_error("Failed to sign certificate");
        }
        
        spdlog::info("Issued certificate for device: {}", csr.device_id);
        return DeviceCertificate(cert);
    }
    
    bool verify_certificate(const DeviceCertificate& cert) const {
        // 验证证书签名
        if (!cert.verify_signature(ca_key_.get())) {
            spdlog::warn("Certificate signature verification failed");
            return false;
        }
        
        // 检查有效期
        if (cert.is_expired()) {
            spdlog::warn("Certificate has expired");
            return false;
        }
        
        // 检查吊销列表
        std::string serial = cert.get_serial_number();
        if (is_revoked(serial)) {
            spdlog::warn("Certificate is revoked: {}", serial);
            return false;
        }
        
        return true;
    }
    
    void revoke_certificate(const std::string& serial_number) {
        std::lock_guard<std::mutex> lock(revoked_certs_mutex_);
        revoked_certs_.insert(serial_number);
        spdlog::info("Certificate revoked: {}", serial_number);
        
        // 持久化吊销列表
        persist_crl();
    }

private:
    void add_extensions(X509* cert, const CertificateSigningRequest& csr) {
        X509V3_CTX ctx;
        X509V3_set_ctx(&ctx, ca_cert_.get(), cert, nullptr, nullptr, 0);
        
        // 基本约束
        add_extension(cert, &ctx, NID_basic_constraints, "CA:FALSE");
        
        // 密钥用途
        add_extension(cert, &ctx, NID_key_usage, 
                      "digitalSignature,keyEncipherment");
        
        // 扩展密钥用途
        add_extension(cert, &ctx, NID_ext_key_usage, 
                      "clientAuth");
        
        // 主体密钥标识符
        add_extension(cert, &ctx, NID_subject_key_identifier, "hash");
        
        // 授权密钥标识符
        add_extension(cert, &ctx, NID_authority_key_identifier, 
                      "keyid:always,issuer:always");
        
        // 自定义扩展:设备ID
        std::string device_id_ext = "DeviceID:" + csr.device_id;
        // 使用自定义OID或注释字段存储
    }
    
    void add_extension(X509* cert, X509V3_CTX* ctx, int nid, 
                       const char* value) {
        X509_EXTENSION* ext = X509V3_EXT_conf_nid(nullptr, ctx, nid, 
                                                   const_cast<char*>(value));
        if (ext) {
            X509_add_ext(cert, ext, -1);
            X509_EXTENSION_free(ext);
        }
    }
    
    bool is_revoked(const std::string& serial) const {
        std::lock_guard<std::mutex> lock(revoked_certs_mutex_);
        return revoked_certs_.find(serial) != revoked_certs_.end();
    }
    
    void persist_crl() {
        // 持久化吊销证书列表到文件或数据库
        // 实现省略...
    }
    
    std::unique_ptr<X509, decltype(&X509_free)> ca_cert_{nullptr, X509_free};
    std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> ca_key_{nullptr, EVP_PKEY_free};
    
    mutable std::mutex revoked_certs_mutex_;
    std::unordered_set<std::string> revoked_certs_;
};

CertificateAuthority::CertificateAuthority(
    const std::string& ca_cert_path,
    const std::string& ca_key_path,
    const std::string& passphrase)
    : impl_(std::make_unique<Impl>(ca_cert_path, ca_key_path, passphrase)) {}

CertificateAuthority::~CertificateAuthority() = default;

DeviceCertificate CertificateAuthority::issue_certificate(
    const CertificateSigningRequest& csr,
    int validity_days) {
    return impl_->issue_certificate(csr, validity_days);
}

bool CertificateAuthority::verify_certificate(const DeviceCertificate& cert) const {
    return impl_->verify_certificate(cert);
}

void CertificateAuthority::revoke_certificate(const std::string& serial_number) {
    impl_->revoke_certificate(serial_number);
}

} // namespace aidc::security

双向TLS实现

TLS配置管理

// tls_context.hpp
#pragma once
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string>
#include <memory>
#include <functional>

namespace aidc::security {

// TLS版本
enum class TlsVersion {
    TLS_1_2,
    TLS_1_3,
    AUTO
};

// TLS配置
struct TlsConfig {
    TlsVersion min_version = TlsVersion::TLS_1_2;
    std::string cert_chain_file;      // 证书链文件
    std::string private_key_file;     // 私钥文件
    std::string ca_cert_file;         // CA证书文件(用于验证对方)
    std::string cipher_list;          // 加密套件列表
    bool verify_peer = true;          // 验证对方证书
    bool fail_if_no_peer_cert = true; // 必须提供证书
    int verify_depth = 4;             // 证书链最大深度
    std::chrono::seconds handshake_timeout{30};
};

// TLS上下文管理
class TlsContext {
public:
    explicit TlsContext(const TlsConfig& config);
    ~TlsContext();
    
    // 禁止拷贝
    TlsContext(const TlsContext&) = delete;
    TlsContext& operator=(const TlsContext&) = delete;
    
    // 创建SSL对象
    SSL* create_ssl();
    
    // 获取底层上下文
    SSL_CTX* native_handle() const { return ctx_; }
    
    // 设置证书验证回调
    using VerifyCallback = std::function<bool(X509_STORE_CTX*, void*)>;
    void set_verify_callback(VerifyCallback callback, void* user_data);
    
    // 加载证书吊销列表
    bool load_crl(const std::string& crl_file);
    
    // 启用OCSP Stapling
    bool enable_ocsp_stapling();

private:
    SSL_CTX* ctx_;
    TlsConfig config_;
    VerifyCallback verify_callback_;
    void* verify_user_data_;
    
    void configure_tls_version();
    void configure_cipher_suites();
    static int verify_callback_wrapper(int preverify_ok, X509_STORE_CTX* ctx);
};

// 安全连接
class SecureConnection {
public:
    SecureConnection(SSL* ssl, int socket_fd);
    ~SecureConnection();
    
    // 禁止拷贝,允许移动
    SecureConnection(const SecureConnection&) = delete;
    SecureConnection& operator=(const SecureConnection&) = delete;
    SecureConnection(SecureConnection&& other) noexcept;
    SecureConnection& operator=(SecureConnection&& other) noexcept;
    
    // TLS握手
    enum class HandshakeResult {
        SUCCESS,
        WANT_READ,
        WANT_WRITE,
        FAILED
    };
    
    HandshakeResult do_handshake();
    bool complete_handshake_with_timeout(std::chrono::seconds timeout);
    
    // 获取连接信息
    std::string get_peer_cert_subject() const;
    std::string get_cipher_name() const;
    TlsVersion get_tls_version() const;
    std::vector<uint8_t> get_peer_cert_der() const;
    
    // 发送/接收数据
    ssize_t send(const void* data, size_t len);
    ssize_t receive(void* buffer, size_t len);
    
    // 关闭连接
    void shutdown();
    
    // 检查连接状态
    bool is_established() const;
    int get_error(int ret_code) const;

private:
    SSL* ssl_;
    int socket_fd_;
    bool established_;
};

} // namespace aidc::security

Connect模块TLS服务器实现

// connect_tls_server.cpp
#include "tls_context.hpp"
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <poll.h>
#include <spdlog/spdlog.h>

namespace aidc::connect {

class TlsDeviceServer {
public:
    TlsDeviceServer(const security::TlsConfig& config,
                   std::shared_ptr<security::CertificateAuthority> ca)
        : tls_ctx_(config)
        , ca_(ca)
        , running_(false) {}
    
    bool start(uint16_t port) {
        // 创建监听socket
        listen_fd_ = socket(AF_INET6, SOCK_STREAM, 0);
        if (listen_fd_ < 0) {
            spdlog::error("Failed to create socket");
            return false;
        }
        
        // 设置地址重用
        int reuse = 1;
        setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
        
        // 绑定地址
        sockaddr_in6 addr{};
        addr.sin6_family = AF_INET6;
        addr.sin6_port = htons(port);
        addr.sin6_addr = in6addr_any;
        
        if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
            spdlog::error("Failed to bind to port {}", port);
            close(listen_fd_);
            return false;
        }
        
        // 开始监听
        if (listen(listen_fd_, 128) < 0) {
            spdlog::error("Failed to listen on socket");
            close(listen_fd_);
            return false;
        }
        
        // 设置非阻塞
        int flags = fcntl(listen_fd_, F_GETFL, 0);
        fcntl(listen_fd_, F_SETFL, flags | O_NONBLOCK);
        
        running_ = true;
        accept_thread_ = std::thread(&TlsDeviceServer::accept_loop, this);
        
        spdlog::info("TLS device server started on port {}", port);
        return true;
    }
    
    void stop() {
        running_ = false;
        close(listen_fd_);
        if (accept_thread_.joinable()) {
            accept_thread_.join();
        }
    }
    
    // 设置设备认证回调
    using AuthCallback = std::function<bool(const std::string& device_id,
                                            const std::vector<uint8_t>& cert_der)>;
    void set_auth_callback(AuthCallback callback) {
        auth_callback_ = callback;
    }

private:
    void accept_loop() {
        while (running_) {
            sockaddr_in6 client_addr{};
            socklen_t addr_len = sizeof(client_addr);
            
            int client_fd = accept(listen_fd_, 
                                   reinterpret_cast<sockaddr*>(&client_addr),
                                   &addr_len);
            
            if (client_fd < 0) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                    continue;
                }
                spdlog::error("Accept failed: {}", strerror(errno));
                continue;
            }
            
            // 创建新线程处理连接
            std::thread(&TlsDeviceServer::handle_connection, this, client_fd).detach();
        }
    }
    
    void handle_connection(int client_fd) {
        // 创建SSL对象
        SSL* ssl = tls_ctx_.create_ssl();
        if (!ssl) {
            close(client_fd);
            return;
        }
        
        // 设置文件描述符
        SSL_set_fd(ssl, client_fd);
        
        // 设置验证回调
        SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
        
        security::SecureConnection conn(ssl, client_fd);
        
        // 完成握手
        if (!conn.complete_handshake_with_timeout(std::chrono::seconds(30))) {
            spdlog::warn("TLS handshake failed");
            return;
        }
        
        // 获取并验证设备证书
        auto cert_der = conn.get_peer_cert_der();
        std::string device_id = extract_device_id(conn.get_peer_cert_subject());
        
        spdlog::info("Device {} connected via TLS 1.3", device_id);
        
        // 验证设备身份
        if (auth_callback_ && !auth_callback_(device_id, cert_der)) {
            spdlog::warn("Device {} authentication failed", device_id);
            return;
        }
        
        // 进入数据传输循环
        handle_device_communication(conn, device_id);
    }
    
    void handle_device_communication(security::SecureConnection& conn,
                                    const std::string& device_id) {
        std::vector<uint8_t> buffer(4096);
        
        while (running_) {
            ssize_t received = conn.receive(buffer.data(), buffer.size());
            
            if (received <= 0) {
                int ssl_error = conn.get_error(static_cast<int>(received));
                if (ssl_error == SSL_ERROR_WANT_READ || 
                    ssl_error == SSL_ERROR_WANT_WRITE) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(1));
                    continue;
                }
                break;
            }
            
            // 处理接收到的数据
            process_device_data(device_id, 
                               std::span(buffer.data(), received));
        }
        
        spdlog::info("Device {} disconnected", device_id);
    }
    
    void process_device_data(const std::string& device_id,
                            std::span<const uint8_t> data) {
        // 解析气象数据包
        // 转发到ISOS模块处理
        // 实现省略...
    }
    
    std::string extract_device_id(const std::string& subject) {
        // 从证书主题提取设备ID
        // 例如:/CN=Station-001/O=AIDC/...
        size_t cn_pos = subject.find("/CN=");
        if (cn_pos != std::string::npos) {
            size_t end = subject.find('/', cn_pos + 4);
            return subject.substr(cn_pos + 4, end - cn_pos - 4);
        }
        return "";
    }
    
    security::TlsContext tls_ctx_;
    std::shared_ptr<security::CertificateAuthority> ca_;
    std::atomic<bool> running_;
    int listen_fd_;
    std::thread accept_thread_;
    AuthCallback auth_callback_;
};

} // namespace aidc::connect

令牌认证机制

JWT令牌实现

// jwt_token.hpp
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include <unordered_map>
#include <optional>

namespace aidc::security {

// JWT令牌结构
class JwtToken {
public:
    using Claims = std::unordered_map<std::string, std::string>;
    
    // 创建令牌
    static std::string create(const std::string& device_id,
                              const std::string& secret_key,
                              std::chrono::seconds validity,
                              const Claims& additional_claims = {});
    
    // 验证令牌
    struct ValidationResult {
        bool valid;
        std::string device_id;
        std::chrono::system_clock::time_point expires_at;
        Claims claims;
        std::string error;
    };
    
    static ValidationResult validate(const std::string& token,
                                     const std::string& secret_key);
    
    // 刷新令牌
    static std::string refresh(const std::string& token,
                               const std::string& secret_key,
                               std::chrono::seconds new_validity);

private:
    static std::string base64_encode(const std::vector<uint8_t>& data);
    static std::vector<uint8_t> base64_decode(const std::string& encoded);
    static std::string sign(const std::string& header_payload,
                           const std::string& secret);
};

// 令牌管理器
class TokenManager {
public:
    explicit TokenManager(std::string secret_key,
                         std::chrono::seconds default_validity = 
                             std::chrono::hours(24));
    
    // 为设备颁发令牌
    std::string issue_token(const std::string& device_id,
                           const JwtToken::Claims& claims = {});
    
    // 验证令牌
    std::optional<JwtToken::ValidationResult> verify_token(
        const std::string& token);
    
    // 吊销令牌
    void revoke_token(const std::string& token);
    
    // 检查令牌是否被吊销
    bool is_revoked(const std::string& token) const;
    
    // 清理过期令牌
    void cleanup_expired();

private:
    std::string secret_key_;
    std::chrono::seconds default_validity_;
    
    mutable std::mutex revoked_mutex_;
    std::unordered_set<std::string> revoked_tokens_;
};

} // namespace aidc::security

gRPC拦截器集成

// grpc_auth_interceptor.hpp
#pragma once
#include <grpcpp/grpcpp.h>
#include <grpcpp/server_context.h>
#include "jwt_token.hpp"

namespace aidc::grpc {

// 认证拦截器
class AuthInterceptor : public grpc::experimental::Interceptor {
public:
    explicit AuthInterceptor(
        grpc::experimental::ServerRpcInfo* info,
        std::shared_ptr<security::TokenManager> token_manager);
    
    void Intercept(grpc::experimental::InterceptorBatchMethods* methods) override;

private:
    std::shared_ptr<security::TokenManager> token_manager_;
    
    bool authenticate(grpc::ServerContext* context);
    std::string extract_token(const std::string& auth_header);
};

// 拦截器工厂
class AuthInterceptorFactory 
    : public grpc::experimental::ServerInterceptorFactoryInterface {
public:
    explicit AuthInterceptorFactory(
        std::shared_ptr<security::TokenManager> token_manager)
        : token_manager_(token_manager) {}
    
    grpc::experimental::Interceptor* CreateServerInterceptor(
        grpc::experimental::ServerRpcInfo* info) override {
        return new AuthInterceptor(info, token_manager_);
    }

private:
    std::shared_ptr<security::TokenManager> token_manager_;
};

} // namespace aidc::grpc

密钥轮转与更新

密钥轮转策略

时间线

T0: 轮转开始

T1+24h: 双密钥并行

T2+48h: 新令牌完成

T3+72h: 旧密钥退休

密钥生命周期

生成新密钥

部署到服务端

同时接受新旧令牌

更新所有设备令牌

移除旧密钥

旧令牌失效

实现代码

// key_rotation.hpp
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include <atomic>

namespace aidc::security {

// 密钥轮转管理器
class KeyRotationManager {
public:
    struct KeyInfo {
        std::string key_id;
        std::string secret;
        std::chrono::system_clock::time_point created_at;
        std::chrono::system_clock::time_point expires_at;
        bool is_active;
    };
    
    explicit KeyRotationManager(std::chrono::hours rotation_interval = 
                                    std::chrono::hours(720)); // 30天
    
    // 启动轮转定时器
    void start_rotation_timer();
    void stop_rotation_timer();
    
    // 手动触发轮转
    void rotate_keys();
    
    // 获取当前活跃密钥
    KeyInfo get_current_key() const;
    
    // 获取用于验证的所有密钥(包括即将过期的)
    std::vector<KeyInfo> get_verification_keys() const;
    
    // 使用指定密钥ID验证
    bool verify_with_key(const std::string& token, 
                        const std::string& key_id);

private:
    void rotation_worker();
    std::string generate_secure_key();
    
    std::atomic<bool> running_;
    std::chrono::hours rotation_interval_;
    
    mutable std::shared_mutex keys_mutex_;
    std::vector<KeyInfo> keys_;
    
    std::thread rotation_thread_;
};

} // namespace aidc::security

AIDC系统中的实现

整体安全架构

服务端安全

传输安全

设备端安全

安全启动

TPM/HSM密钥存储

设备证书

mTLS连接

TCP连接

TLS 1.3握手

双向证书验证

加密数据通道

Connect模块

证书验证

设备身份确认

JWT令牌颁发

gRPC调用

令牌验证

业务处理

设备端TLS客户端

// device_tls_client.hpp
#pragma once
#include <openssl/ssl.h>
#include <string>
#include <vector>
#include <functional>

namespace aidc::device {

class SecureDeviceClient {
public:
    struct Config {
        std::string server_address;
        uint16_t server_port;
        std::string device_cert_file;
        std::string device_key_file;
        std::string ca_cert_file;
        std::chrono::seconds reconnect_interval{30};
        std::chrono::seconds heartbeat_interval{60};
    };
    
    explicit SecureDeviceClient(const Config& config);
    ~SecureDeviceClient();
    
    // 连接服务器
    bool connect();
    void disconnect();
    
    // 发送气象数据
    bool send_observation(const std::vector<uint8_t>& data);
    
    // 发送心跳
    bool send_heartbeat();
    
    // 设置消息回调
    using MessageCallback = std::function<void(const std::vector<uint8_t>&)>;
    void set_message_callback(MessageCallback callback);
    
    // 获取连接状态
    bool is_connected() const;
    std::chrono::system_clock::time_point last_heartbeat() const;

private:
    bool perform_handshake();
    void receive_loop();
    bool verify_server_certificate(X509* cert);
    
    Config config_;
    SSL_CTX* ssl_ctx_;
    SSL* ssl_;
    int socket_fd_;
    std::atomic<bool> connected_;
    std::atomic<bool> should_stop_;
    
    std::thread receive_thread_;
    std::thread heartbeat_thread_;
    MessageCallback message_callback_;
};

} // namespace aidc::device

最佳实践

1. 证书管理清单

// 证书检查清单
class CertificateChecklist {
public:
    static bool validate_production_readiness(const DeviceCertificate& cert) {
        // 检查1: 密钥长度
        if (!has_sufficient_key_size(cert)) {
            spdlog::error("Certificate key size too small");
            return false;
        }
        
        // 检查2: 签名算法
        if (!uses_strong_signature(cert)) {
            spdlog::error("Weak signature algorithm");
            return false;
        }
        
        // 检查3: 有效期
        if (get_validity_days(cert) > 365) {
            spdlog::warn("Certificate validity too long");
        }
        
        // 检查4: 扩展字段
        if (!has_required_extensions(cert)) {
            spdlog::error("Missing required extensions");
            return false;
        }
        
        return true;
    }
    
private:
    static bool has_sufficient_key_size(const DeviceCertificate& cert);
    static bool uses_strong_signature(const DeviceCertificate& cert);
    static int get_validity_days(const DeviceCertificate& cert);
    static bool has_required_extensions(const DeviceCertificate& cert);
};

2. 安全编码实践

// 安全编码检查点
namespace security_best_practices {

// 1. 永不硬编码密钥
// 错误:
// const char* SECRET_KEY = "hardcoded_secret";
// 正确:
// 从环境变量或安全存储读取
std::string load_secret_from_env() {
    const char* secret = std::getenv("AIDC_JWT_SECRET");
    if (!secret) {
        throw std::runtime_error("JWT secret not configured");
    }
    return std::string(secret);
}

// 2. 使用安全随机数生成器
std::vector<uint8_t> generate_secure_random(size_t length) {
    std::vector<uint8_t> buffer(length);
    if (RAND_bytes(buffer.data(), length) != 1) {
        throw std::runtime_error("Failed to generate secure random");
    }
    return buffer;
}

// 3. 常量时间比较(防时序攻击)
bool constant_time_compare(const std::string& a, const std::string& b) {
    if (a.size() != b.size()) return false;
    
    volatile unsigned char result = 0;
    for (size_t i = 0; i < a.size(); ++i) {
        result |= a[i] ^ b[i];
    }
    return result == 0;
}

// 4. 安全的内存清零
void secure_clear(void* ptr, size_t len) {
    OPENSSL_cleanse(ptr, len);
}

template<typename T>
void secure_clear(T& obj) {
    secure_clear(&obj, sizeof(T));
}

} // namespace security_best_practices

3. 监控与审计

// 安全事件审计
class SecurityAuditor {
public:
    enum class EventType {
        DEVICE_AUTHENTICATED,
        DEVICE_AUTH_FAILED,
        CERTIFICATE_EXPIRED,
        CERTIFICATE_REVOKED,
        SUSPICIOUS_ACTIVITY,
        TOKEN_REFRESHED,
        TOKEN_REVOKED
    };
    
    void log_event(EventType type,
                  const std::string& device_id,
                  const std::string& details);
    
    // 异常检测
    void detect_anomalies();
    
private:
    struct SecurityEvent {
        EventType type;
        std::string device_id;
        std::string details;
        std::chrono::system_clock::time_point timestamp;
    };
    
    std::vector<SecurityEvent> events_;
    mutable std::mutex events_mutex_;
};

总结

本文详细介绍了AIDC自动气象站数据收集系统中的物联网设备身份认证与安全通信方案。通过实施以下安全措施,我们构建了一个可靠的安全体系:

  1. X.509证书体系:基于PKI的强身份认证,确保设备身份可信
  2. 双向TLS 1.3:提供加密传输和双向身份验证
  3. JWT令牌机制:无状态的会话管理,支持细粒度访问控制
  4. 密钥轮转策略:定期更新密钥,降低密钥泄露风险
  5. 安全审计:完整的日志记录和异常检测

安全是一项持续的工作,建议定期进行安全评估和渗透测试,确保系统始终符合最新的安全标准。


https://github.com/0voice

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐