Files
STP/docs/architecture/招标系统-加密-开发使用.md
T

21 KiB
Raw Blame History

滨化集团智慧招标平台(STP)数据安全机制设计


1. 总体安全策略与目标

为确保招标全流程数据的机密性、完整性和可用性,针对内外部威胁(包括具备服务器操作权限的开发人员、DBA、运维人员),建立 “数据全程加密、密钥动态漂移、权限最小化、AI按需脱敏” 的纵深防御体系。所有加密与密钥管理均在应用层和内存中实现。

核心目标

  • 防窥探:即使攻击者获得服务器操作权限,也无法直接读取数据库中的招标敏感数据(如投标报价、专家打分、关联关系图谱)。
  • 防泄露:静态文件加密存储,传输全程TLS 1.3加密,密钥在内存中动态漂移,杜绝落盘。
  • 防越权:前后端双重权限校验,AI Agent仅能通过流程状态门控获取被授权数据,禁止通过对话方式旁路获取受限信息。
  • 可审计:所有数据访问、密钥迁移、AI调用行为均记录不可篡改日志(使用哈希链+数字签名代替区块链)。

2. 密钥管理机制:内存动态漂移 + 应用层分割

2.1 设计原则

  • 密钥永不落盘:加密密钥(数据密钥、文件密钥)仅在服务器内存中生成和存储,禁止写入任何持久化存储(磁盘、SSD、数据库)。
  • 动态漂移:密钥的存储内存地址每隔若干小时随机迁移,同时变更密钥本身(旧密文使用旧密钥解密后使用新密钥重加密),降低内存被暴力扫描窃取的风险。
  • 密钥分割:单条数据密钥被分割为2~3个分片,保存在不同进程/容器的内存区域,使用时分片聚合,用完即时销毁。

2.2 具体实现

组件 技术方案
数据加密密钥 (DEK) 每条招标项目、投标文件、专家评分记录使用独立 DEK。DEK 由应用服务在内存中随机生成,永不落盘。DEK 的密文可存储于数据库,但主密钥仅在内存中。
主密钥 (MEK) 每个微服务实例启动时,从配置中心读取一个种子口令,通过 PBKDF2 派生出一个 32 字节的主密钥,仅存于内存。该主密钥用于加密所有 DEK。主密钥不漂移,但服务重启时会重新派生。
密钥分割 不使用复杂的秘密共享算法,简化实现:将 32 字节 DEK 切分为两段各 16 字节,分别存放于两个不同微服务容器的内存中。需要解密时,两个片段临时聚合,用完后立即清零。
内存漂移调度器 独立微服务 KeyDrifter,每 4 小时(可配置)触发:
1. 扫描所有活跃 DEK 标识;
2. 生成新的随机内存地址(不同进程/堆区域),生成新 DEK;
3. 从旧地址读取旧 DEK,解密数据后用新 DEK 重加密,并将加密后 DEK 存回数据库;
4. 更新内存索引,清零旧内存区域。
内存保护 使用 mlock() 系统调用锁定内存页,防止被 swap 到磁盘;使用 mprotect() 设置非执行权限;敏感内存区域使用 zeroize 库在释放前覆盖。

2.3 密钥生命周期

[生成] 首次写入加密字段时,由应用服务生成 DEK(随机字节) → 分割为两片段 → 分片存入不同服务内存。
[使用] 业务服务请求解密 → 聚合分片 → 解密后立即销毁聚合缓存。
[漂移] KeyDrifter 锁住当前进程内存 → 新内存区生成新 DEK → 复制数据并重加密 → 更新数据库中的密文(DEK 仍使用同一个 MEK 加密存储) → 释放旧区。
[销毁] 项目归档期满后,删除 DEK 内存引用,内存页清零,数据库中对应的加密 DEK 字段标记为已删除(但物理数据无法解密)。

3. 静态数据加密

3.1 数据库加密

加密粒度 实施方案
透明加密 使用磁盘加密作为基础防护,防止物理磁盘被盗。但透明加密不防止 DBA 直接读取数据库文件,因此仍需字段级加密。
字段级加密 对极端敏感字段采用应用层字段加密:每个字段使用独立 DEK,DEK 密文存储在同一行的单独列中。加密算法:AES-256-GCM,附加认证数据(AAD)为表名+行ID。
索引混淆 加密字段不能直接用于条件查询,采用确定性加密生成可搜索的盲索引,盐值也存在于内存中,定期轮换并重建索引。

3.2 静态文件加密

所有上传文件(投标书PDF、资质扫描件、专家承诺书、音视频记录)采用信封加密:

  1. 每个文件随机生成文件密钥,内存中保存。
  2. 使用 FEK 对文件进行AES-256-GCM加密,分块上传(每块 4MB),每块独立加密。
  3. FEK 使用主密钥加密后,作为文件元数据的一部分存储于对象存储的 metadata 字段或单独数据库表。
  4. 文件在对象存储中始终处于密文状态,即使直接拷贝也无法读取。
  5. 文件访问时,应用服务器从内存中获取 MEK → 解密 FEK → 用 FEK 解密文件流 → 传输给授权前端,不落地。

3.3 备份与快照加密

  • 数据库备份、对象存储快照必须使用独立的备份密码。
  • 备份密钥由双人控制(分段存储于两个保险柜),恢复时需要两人输入各自的密码段。

4. 传输加密与 API 安全

4.1 全链路 TLS 1.3

  • 所有对外服务(前端、API、Webhook)强制启用 TLS 1.3,禁用弱密码套件。
  • 使用内部 CA 签发服务端证书,客户端验证服务端证书指纹。
  • 服务间调用(微服务、AI Agent)采用 mTLS,双向认证。

4.2 API 请求签名

  • 对外 API(供应商、第三方系统)需使用 OAuth2.0 Client Credentials 获取 token,请求头携带 Authorization: Bearer <jwt>
  • 对关键操作(上传投标、修改报价)额外要求 请求签名HMAC-SHA256(requestBody + timestamp + nonce, clientSecret),服务器校验签名及时间窗口(≤ 5 分钟)。

4.3 前端通信加密增强

  • WebSocket 传输实时打分数据时,在 TLS 之上再次进行应用层非对称加密(使用服务器公钥加密 payload),即使 TLS 被中间人破解,也无法直接解析业务数据。

5. 前后端权限隔离与角色端口设计

5.1 角色与端口映射

平台为不同角色分配独立的访问端口(或子域名),并在网关层绑定最小权限策略:

5.2 前后端双重权限校验

  • 前端:登录后获取 JWT,JWT 中仅包含角色和用户 ID,不包含任何权限矩阵。前端根据角色代码展示不同菜单,但关键按钮(如“查看报价”)仍需要后端二次确认。
  • 后端:每个 API 调用都会执行 Policy Enforcement Point (PEP),根据用户 ID + 资源 ID 查询:
    • 用户是否属于该项目的相关角色(如:该专家是否被分配到该项目评委组)
    • 当前流程状态是否允许访问该资源(例如:开标前任何人不能查看报价文件)
    • 使用 CasbinOPA 实现动态规则引擎,规则可热更新。

6. AI Agent 安全隔离与按需数据访问

6.1 角色独立 AI Agent 架构

每个角色(供应商、专家、招标专员、审批人、管理员)分别部署一个独立的 AI Agent 容器,使用不同的 API Key 和身份凭证。Agent 之间的内存和密钥完全隔离。

6.2 流程驱动的数据门控

Agent 在调用任何业务数据前,必须通过统一数据网关验证请求合法性。网关检查:

  1. 角色匹配:Agent 的 JWT 中角色声明是否与目标数据要求一致。
  2. 流程状态:查询招标项目的工作流引擎当前状态,根据前述“状态门控”决定是否放行。
  3. 数据脱敏:即使允许访问,返回的数据也会根据角色自动脱敏(如专家 Agent 只能看到技术标中隐去供应商名称的版本)。

调用时序示例(专家 Agent 获取技术标):

sequenceDiagram
    participant ExpertAgent
    participant DataGateway
    participant WorkflowEngine
    participant FileService

    ExpertAgent->>DataGateway: GET /tender/T001/tech_bid?projectId=...
    DataGateway->>WorkflowEngine: query project stage
    WorkflowEngine-->>DataGateway: stage = "evaluating"
    DataGateway->>DataGateway: 校验专家是否属于该项目评委组(内存中缓存)
    DataGateway->>FileService: 获取加密文件流
    FileService-->>DataGateway: 密文流 + 解密用 FEK(内存获取)
    DataGateway->>DataGateway: 解密 -> 移除供应商名称、LogoNLP 脱敏)
    DataGateway-->>ExpertAgent: 脱敏后的技术标

6.3 AI 对话隔离:防止越狱查询

当流程状态为“数据不可见”时,AI Agent 进入教学/流程提醒模式:

  • Agent 的上下文(system prompt)强制注入:当前阶段禁止透露任何项目数据,包括报价、投标人名称、评分。若用户询问数据,统一回答:“暂未到查看时间,请等待系统通知。如需帮助,请描述您的问题(如:如何上传文件?)”。
  • 后端增加对话内容审计:每次用户询问,AI Agent 先将问题发送至越狱检测服务(基于语义相似度和正则),命中敏感词(“报价”、“分数”、“谁中标了”)且当前流程禁止时,直接拦截并记录异常日志。
  • 对于普通操作教学(“如何修改密码”),使用独立的“小滨-助手”知识库(不含任何项目数据),不涉及数据查询。

架构示意

用户对话 → API网关 → 角色Agent → [对话安全过滤器] → 若允许,则查询数据网关;否则,仅调用公共知识库RAG。

6.4 Agent 调用审计

  • 记录每个 Agent 发起的每一次数据请求(包括时间、项目ID、请求参数、返回数据指纹)。
  • 审计日志写入哈希链日志表,防止管理员篡改。

7. 防开发人员/DBA 窥探的硬性措施

即使开发人员拥有服务器 root 权限或数据库管理员权限,也无法直接读取明文敏感数据。

7.1 数据库层面

  • 应用层加密:数据库管理员看到的 price_enc 字段是 Base64 乱码,没有内存中的 DEK 无法解密。
  • 数据库连接账户隔离DBA 使用的 root 账户无法访问应用表(通过数据库行级安全策略 RLS 禁止),应用使用单独的 app_user 账户,该账户密码存放在配置中心(如 Vault),开发人员无法直接获取。
  • 查询审计:数据库审计插件记录所有 SELECT 操作,若发现 DBA 批量查询加密字段,自动告警并冻结账户。

7.2 服务器与内存

  • 禁止交互式 shell:生产服务器禁止开发人员直接 SSH 登录,所有操作必须通过堡垒机 + 动态令牌,且操作全程录像。
  • 内核安全模块:使用 SELinux/AppArmor 限制只有 stp-app 进程可读取 /proc/self/mem 中特定内存区域,其他进程(包括开发人员启动的调试器)无权限。
  • 内存转储禁止:内核参数设置 vm.dumpable = 0,防止 ptracegcore 导出内存内容。
  • 动态漂移:密钥每 4 小时迁移到不同进程内存,攻击者即使获得了某一时刻的内存快照,也只能看到已失效的密钥或分片。

7.3 开发与调试环境

  • 脱敏数据镜像:开发测试环境使用完全脱敏的伪造数据(通过数据脱敏工具生成),不包含真实供应商、报价。
  • 密钥沙盒:开发环境使用独立的种子口令,无法接触生产密钥。
  • CI/CD 隔离:构建流水线中使用的变量(如数据库密码)来自 Vault 动态 secret,构建完成后立即失效。

8. 审计与监控(无区块链,改用哈希链)

8.1 审计日志保护(哈希链 + 数字签名)

不使用区块链,而是采用 哈希链 + 数字签名 保证日志不可篡改:

  • 每条审计日志记录包含:id时间操作者操作内容数据指纹
  • 每条日志的 prev_hash 字段指向前一条日志的哈希。
  • 每小时,系统对当前哈希链的最新哈希值,使用审计专用私钥进行签名,并将签名值保存到外部(如另一个数据库表或文件)。
  • 验证时,重新计算哈希链,比对签名。

8.2 审计内容范围

审计对象 采集内容 保留期限 存储方式
用户访问日志 谁、何时、从哪个 IP、访问了哪个 API、返回了哪类数据(脱敏后指纹) 7 年 哈希链日志表 + 离线归档
密钥操作日志 密钥生成时间、漂移时间、销毁时间、涉及的内存地址范围(经过哈希) 3 年 加密存储,仅合规人员可读
AI Agent 调用日志 Agent 角色、请求参数、是否被拦截、越狱检测结果 3 年 同上
数据库 DDL/DML 所有 INSERT/UPDATE/SELECT 敏感表记录 永久 同步至独立 SIEM
异常告警 单用户异常访问、密钥漂移失败次数 实时推送 飞书/短信通知安全运维

9. 存证功能

9.1 存证目标与原则

  • 独立存证表:存证记录独立于业务数据库,使用哈希链防止篡改。
  • 可信时间戳:对关键存证事件,调用第三方可信时间戳服务赋予法律效力。
  • 与加密机制协同:存证哈希基于解密后的明文(但只传哈希,不传明文)。

9.2 存证范围与触发事件

阶段 存证事件 存证内容(哈希对象) 触发时机
委托 招标委托单提交审批 委托单全文JSON 用户点击“发起审批”
委托审批通过 审批记录+签字意见 OA回调“审批完成”
立项 招标方案确认 招标方案PDF 立项审批通过
供应商短名单确认 短名单(供应商ID+推荐理由) 短名单审批完成
文件编制 招标文件定稿 招标文件PDF 文件加密发布前
澄清/修改公告 澄清文件PDF 发布前
投标 投标文件上传完成 投标文件哈希+上传时间戳 供应商上传加密文件成功后
保证金缴纳凭证 银行回单PDF 支付网关回调成功
开标 开标记录 开标现场音视频文件哈希+关键截屏 开标结束时
评标 评委打分 每个评委的评分表(含打分项) 评委提交评分
偏离度复核记录 AI提醒+评委确认意见 评委复核确认
定标 评标报告 评标报告PDF 报告定稿
中标结果审批 定标审批单+领导签字 定标审批通过
合同 合同签订 电子合同PDF 双方电子签章完成
归档 全项目归档包 所有存证哈希组成的Merkle树根 归档完成时

9.3 存证技术方案

层级 技术 用途 成本
第一层:内部哈希链 SHA-256 + 前后哈希引用 内部防止日志篡改,快速验证,无需外部依赖
第二层:可信时间戳 联合信任时间戳、腾讯云时间戳等 赋予法律效力,诉讼时可出证 按次收费,约1-5元/次(仅重大项目调用)

9.4 存证数据结构

{
  "evidence_id": "E_20260602_001",
  "project_id": "T2026001",
  "event_type": "bid_submit",
  "event_time": "2026-06-02T10:30:00Z",
  "content_hash": "sha256:7b3d...f2a1",
  "content_meta": {
    "file_name": "技术标.pdf",
    "file_size": 2048576,
    "original_storage_path": "encrypted://minio/bucket/..."
  },
  "signature": {
    "signer": "system_evidence",
    "signature_value": "base64..."
  },
  "prev_evidence_hash": "E_20260601_099_hash",
  "cur_hash": "sha256:...",
  "timestamp_proof": "https://timestamp.com/verify?hash=..."   // 可选,仅重大项目
}

9.5 存证流程(以投标文件上传为例)

sequenceDiagram
    participant Supplier
    participant STP_App
    participant Encryptor
    participant Evidence_Service
    participant TimeStamp_API

    Supplier->>STP_App: 上传加密投标文件
    STP_App->>Encryptor: 获取文件明文(临时解密)
    Encryptor-->>STP_App: 明文流
    STP_App->>STP_App: 计算 SHA-256(明文)
    STP_App->>Encryptor: 销毁明文流
    STP_App->>Evidence_Service: 发送存证请求(含哈希、项目ID、事件类型)
    Evidence_Service->>Evidence_Service: 计算当前哈希链
    Evidence_Service->>Evidence_Service: 签名(使用存证专用私钥)
    Evidence_Service->>TimeStamp_API: 提交哈希值(仅关键事件)
    TimeStamp_API-->>Evidence_Service: 返回时间戳证明URL
    Evidence_Service->>STP_App: 存证完成,返回 evidence_id
    STP_App->>Supplier: 上传成功,存证ID已记录

9.6 验证与司法出证

  • 内部验证:在平台“存证验证”页面输入项目号,系统重新计算当前数据哈希,与存证哈希比对,显示“通过”或“篡改”。
  • 司法出证:管理员导出指定项目的完整存证包(含所有事件的哈希链、签名、时间戳证书),提交法院。法院可通过第三方时间戳官网核验。

10. 与现有加密方案的集成点

现有安全组件 存证集成方式
内存密钥漂移 存证服务使用独立内存区域,不参与漂移。密钥仍由 MEK 保护,无KMS。
字段级加密 存证时对解密后的业务含义(如报价金额数字)进行哈希,解密过程在安全沙箱中完成,用完即毁。
文件加密存储 存证哈希基于文件解密后内容计算。验证时,先解密文件,再比对哈希。
AI Agent 数据门控 AI Agent 不能查询存证哈希值,只能由审计角色访问存证服务。
前后端权限隔离 存证服务单独开放端口,仅审计角色和系统管理员可调用。

11. 应急响应与备份

11.1 密钥丢失恢复

主密钥(MEK)派生自种子口令。若所有服务内存崩溃导致 MEK 丢失:

  • 使用离线备份的种子口令(分段保存在不同保险柜,需双人提供)重新派生 MEK。
  • 数据库中存储的 DEK 密文(用 MEK 加密)可以恢复,因为 MEK 不变(种子相同)。
  • 种子口令生成后,使用 Shamir 秘密共享分割为5份,交给5个不同负责人。恢复时需要至少3人提供片段。

11.2 数据备份

  • 全量备份(加密)每天一次,保留30天。
  • 增量备份每6小时一次。
  • 备份密钥由种子口令派生,恢复时需双人授权。
  • 备份恢复演习每季度一次。

11.3 入侵响应

检测到内存扫描、暴力破解、异常数据导出行为 → 自动触发 应急模式

  • 冻结当前所有用户会话
  • 强制销毁所有内存中的 DEK(触发全部数据锁定)
  • 通知安全团队介入

附录:加密机制全流程数据流示意图

graph LR
    subgraph Client
        A[前端/供应商]
    end

    subgraph DMZ
        B[API网关<br>TLS + 签名验证]
        C[WAF]
    end

    subgraph K8s集群
        subgraph UserService[用户服务]
            D[认证服务<br>颁发JWT]
        end
        subgraph BizService[业务微服务]
            E[招标服务]
            F[投标服务]
            G[评分服务]
        end
        subgraph KeyDrifter[KeyDrifter]
            H[密钥漂移器<br>内存管理]
        end
        subgraph AIAgents[AI Agents]
            I[独立角色Agent]
            J[越狱检测器]
        end
        subgraph DataLayer[Data Layer]
            K[(加密数据库<br>字段级密文)]
            L[(加密对象存储<br>MinIO)]
        end
        subgraph EvidenceLayer[存证层]
            M[存证服务]
            N[(哈希链日志表)]
            O[可信时间戳API<br>(可选)]
        end
        P[内存密钥池<br>(无KMS,应用管理)]
    end

    A --> B --> C --> D
    C --> E
    E <--> P
    E --> K
    F --> L
    G --> P
    H --> P
    I --> J
    I --> E
    I --> G

    E -.->|关键事件| M
    F -.->|投标文件| M
    G -.->|评分| M
    M --> N
    M -.-> O