- 添加JWT/加密/速率限制安全配置 - 为所有API添加OpenAPI文档注解 - 建立统一的6位错误码体系 - 实现账务原子更新(乐观锁重试机制) - 添加Swagger UI和请求ID中间件 Ref: #安全配置 #API文档 #错误处理
24 KiB
金融系统安全审计专家审核报告
一、审核概述
作为安全审计专家团队,我们对银行系统的数据安全、访问控制、审计日志、身份认证、敏感数据保护等方面进行了全面审核。本次审核重点关注系统是否符合中国人民银行《金融数据安全数据安全分级指南》、《网络安全法》、以及金融行业对信息系统的安全要求。
1.1 审核范围
本次安全审核覆盖了系统的所有安全相关组件,包括:身份认证与授权机制、数据传输加密、敏感数据保护、审计日志完整性、API安全、数据库安全配置、以及密钥管理等方面。通过对源代码和配置的深入分析,我们评估了系统在安全防护方面的健壮性。
1.2 审核依据
本次审核主要依据以下法规和标准:《中华人民共和国网络安全法》、《中华人民共和国数据安全法》、《金融数据安全数据安全分级指南》(JR/T 0197-2020)、《信息安全技术网络安全等级保护基本要求》(GB/T 22239-2019)、以及银行业信息科技风险管理相关指引。
二、身份认证与授权机制评估
2.1 认证机制分析
通过代码审查,我们发现系统当前版本缺少完整的身份认证机制。在api目录下,所有Handler实现均未看到JWT Token验证、Session管理或其他身份认证逻辑的集成:
pub async fn list_subjects(
State(state): State<AppState>,
) -> Result<Json<SuccessResponse<Vec<SubjectResponse>>>> {
// 直接执行业务逻辑,无身份认证检查
let service = state.ledger_service();
let subjects = service.list_subjects().await?;
// ...
}
这是一个严重的安全漏洞。所有API端点当前都是开放的,任何人都可以直接调用系统功能,包括账户余额查询、交易创建、分录过账等敏感操作。在生产环境中,这可能导致未授权访问、数据泄露、甚至资金损失。
建议立即实施以下措施:第一,集成JWT(JSON Web Token)或OAuth 2.0认证机制,在每个API Handler入口处验证请求的合法性;第二,实现基于角色的访问控制(RBAC),根据用户角色限制可访问的功能和数据;第三,配置API网关进行统一的认证和授权处理,将安全逻辑与业务逻辑分离。
2.2 授权模型设计
即使未来添加身份认证,当前的代码设计也缺少授权控制机制。系统未定义用户角色、权限分配、功能访问控制列表等授权模型。假设用户A已通过认证,他是否有权限查询所有账户的余额?是否有权限执行冲正操作?这些授权决策目前没有明确的规则支持。
建议设计并实现以下授权模型:
// 角色定义
pub enum Role {
Admin, // 管理员:所有权限
Operator, // 操作员:日常操作权限
Auditor, // 审计员:只读权限
Viewer, // 查看者:有限查看权限
}
// 权限定义
pub enum Permission {
ViewBalance,
CreateTransaction,
ApproveAdjustment,
ExecuteReversal,
ViewAuditLog,
}
// 基于角色的访问控制
pub fn check_permission(role: Role, permission: Permission) -> bool {
match role {
Role::Admin => true, // 管理员拥有所有权限
Role::Operator => matches!(permission,
Permission::ViewBalance | Permission::CreateTransaction),
Role::Auditor => matches!(permission, Permission::ViewAuditLog),
Role::Viewer => matches!(permission, Permission::ViewBalance),
}
}
2.3 敏感操作的多因素认证
对于高风险操作(如大额转账、账户冻结、冲正操作),建议增加多因素认证(MFA)机制。这不仅是安全最佳实践,也是监管要求的合规项。
建议对以下操作强制要求多因素认证:单笔超过指定金额的交易、账户状态变更操作、冲正和手工补录操作、敏感数据导出操作、配置变更操作。
三、敏感数据保护评估
3.1 敏感数据识别
根据《金融数据安全数据安全分级指南》,系统中的以下数据属于敏感或高敏感级别数据:
第一级(高敏感):账户密码、支付密码、银行卡号、CVV码、用户身份信息、交易密码。
第二级(敏感):账户余额、交易金额、交易记录、身份证号、联系电话、账户状态。
第三级(一般敏感):会计科目代码、分录编号、操作日志。
通过代码审查,我们发现系统在敏感数据保护方面存在以下问题:
3.2 密码与认证信息处理
查看银行集成模块mock_bank.rs,我们注意到密码和认证信息在代码中以明文形式存储:
pub struct FailureConfig {
pub timeout_rate: f64,
pub failure_rate: f64,
pub duplicate_rate: f64,
pub delay_ms: Range<u64>,
pub enabled: bool,
}
虽然这是测试用的Mock实现,但生产环境的银行认证信息(如API密钥、证书密码)必须进行加密存储。建议使用专用的密钥管理服务(如HashiCorp Vault、AWS KMS)存储敏感认证信息,避免硬编码或明文存储。
3.3 错误信息中的敏感数据泄露
系统的错误处理存在敏感数据泄露风险。在error.rs中:
AppError::InsufficientBalance {
available,
required
} => {
(StatusCode::BAD_REQUEST, "INSUFFICIENT_BALANCE", self.to_string())
}
错误信息直接暴露了账户的可用余额和所需金额。在生产环境中,攻击者可能通过观察错误信息推断账户余额分布,进行针对性的攻击。建议对错误信息进行脱敏处理,只返回错误类型和通用信息,详细错误记录在服务端日志中。
3.4 敏感数据脱敏
在API响应中,敏感数据应当进行脱敏处理:
// 账户信息响应
pub struct AccountResponse {
pub account_no: String, // 脱敏:6222 **** **** 1234
pub account_name: String, // 脱敏:张**
pub balance: Decimal, // 敏感:保留,但限制查询权限
pub bank_code: String, // 一般
}
建议实现统一的脱敏机制,在API层对响应数据进行脱敏处理,确保敏感信息不会通过网络响应泄露。
3.5 日志中的敏感数据
系统的日志记录可能包含敏感数据。查看ledger/service.rs中的日志:
info!("账户 {}({:?}) 冻结金额 {}", account_id, account_type, amount);
warn!("不变量校验失败: 差异 {}, 来源: {}", diff, trigger_source);
虽然当前日志未直接记录敏感数据,但建议增加日志审查机制,确保日志中不会意外包含密码、银行卡号、身份证号等敏感信息。建议在代码审查清单中增加日志审查项,在代码合并前检查日志内容。
四、审计日志完整性评估
4.1 审计日志现状
金融系统必须具备完整的审计日志能力,确保所有关键操作可追溯。系统目前的审计日志实现如下:
第一,交易操作日志。ledger/service.rs中记录了关键操作的info级别日志:
info!("创建记账分录: {} (关联交易: {})", saved_entry.entry_no, saved_entry.txn_no);
info!("账户 {}({:?}) 冻结金额 {}", account_id, account_type, amount);
第二,不变量校验日志。当不变量校验失败时,系统记录警告日志:
warn!("不变量校验失败: 账户 {}({:?}), 差异 {}, 来源: {}",
balance.account_id, balance.account_type, diff, trigger_source);
第三,数据库迁移脚本中定义了invariant_check_log表(第110-124行),用于记录不变量校验的历史:
CREATE TABLE invariant_check_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
account_id BIGINT NOT NULL,
check_time DATETIME DEFAULT CURRENT_TIMESTAMP,
personal_balance DECIMAL(20,2) NOT NULL,
labor_balance DECIMAL(20,2) NOT NULL,
frozen_balance DECIMAL(20,2) NOT NULL,
bank_balance DECIMAL(20,2) NOT NULL,
transit_amount DECIMAL(20,2) NOT NULL,
is_valid TINYINT(1) NOT NULL,
difference DECIMAL(20,2),
trigger_source VARCHAR(100)
);
4.2 审计日志缺陷
尽管系统已有基础的日志能力,但与金融行业的审计要求相比,存在以下明显不足:
第一,审计日志内容不完整。关键操作(如用户登录、权限变更、大额交易、对账审批)的审计日志缺失。目前的日志仅记录了系统内部的业务操作,未记录用户操作审计。
第二,缺少操作人标识。所有日志都记录了操作内容,但未记录操作人(用户ID、用户名、IP地址等)。在金融审计中,必须能够追溯"谁在什么时间做了什么操作"。
第三,审计日志防篡改能力不足。审计日志存储在数据库中,与业务数据使用相同的存储。如果攻击者获得了数据库访问权限,可以修改或删除审计日志。建议使用独立的审计日志存储(如写入专用日志服务或append-only存储)。
第四,未实现审计日志的完整性校验。建议定期计算审计日志的哈希值并存储,用于检测日志是否被篡改。
4.3 审计日志改进建议
建议实现以下完整的审计日志框架:
// 审计日志结构
pub struct AuditLog {
pub id: i64,
pub timestamp: DateTime<Utc>,
pub user_id: Option<i64>, // 操作人ID
pub user_name: Option<String>, // 操作人姓名
pub user_ip: String, // 操作IP地址
pub operation: String, // 操作类型
pub resource_type: String, // 资源类型
pub resource_id: String, // 资源ID
pub old_value: Option<Json>, // 变更前值
pub new_value: Option<Json>, // 变更后值
pub result: AuditResult, // 操作结果
pub remark: Option<String>, // 备注
}
// 审计日志宏
#[macro_export]
macro_rules! audit_log {
($operation:expr, $resource_type:expr, $resource_id:expr, $old:expr, $new:expr) => {
// 记录审计日志到独立存储
};
}
建议审计以下关键操作:用户登录和登出、权限变更和角色分配、账户创建和状态变更、大额交易和转账操作、分录创建和冲正操作、对账审批和手工补录、系统配置变更、数据导出操作。
五、API安全评估
5.1 API安全现状
当前系统的API层实现较为简单,存在以下安全问题:
第一,缺少身份认证。所有API端点直接暴露,没有任何认证机制。第二,缺少速率限制。未实现请求频率限制,可能遭受暴力破解或DDoS攻击。第三,缺少输入验证。API参数验证主要依赖业务层的校验,可能存在注入风险。第四,缺少敏感操作防护。敏感API(如删除、修改状态)未增加额外的安全控制。
5.2 API安全建议
针对API安全,建议实施以下措施:
第一,实现请求速率限制:
// 速率限制配置
pub struct RateLimitConfig {
pub requests_per_minute: u32,
pub burst_size: u32,
pub block_duration_seconds: u32,
}
// 不同端点配置不同的速率限制
pub const API_RATE_LIMITS: &[(HttpMethod, &str, RateLimitConfig)] = &[
(HttpMethod::GET, "/api/v1/accounts", RateLimitConfig {
requests_per_minute: 100,
burst_size: 20,
block_duration_seconds: 60,
}),
(HttpMethod::POST, "/api/v1/transactions", RateLimitConfig {
requests_per_minute: 50,
burst_size: 10,
block_duration_seconds: 120,
}),
];
第二,实现完整的输入验证:
// 输入验证示例
#[derive(Deserialize)]
pub struct CreateTransactionRequest {
pub from_account_id: i64,
pub to_account_id: i64,
#[serde(validate(range(min = 0.01, max = 1000000.00)))]
pub amount: Decimal,
pub remark: Option<String>,
}
// 使用validator crate进行参数校验
第三,实现API响应脱敏:
// 统一响应脱敏处理
pub fn sanitize_response<T: Serialize>(data: T) -> Json<SuccessResponse<T>> {
// 对敏感字段进行脱敏处理
Json(SuccessResponse::new(data))
}
第四,禁用敏感信息泄露:
// 错误响应脱敏
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, code, message) = match &self {
// 详细错误信息仅在开发环境返回
AppError::Database(e) => (
StatusCode::INTERNAL_SERVER_ERROR,
"DATABASE_ERROR",
if cfg!(debug_assertions) { format!("{:?}", e) } else { "数据库操作失败".to_string() }
),
// ... 其他错误处理
};
// ...
}
}
5.3 传输层安全
虽然当前代码中未直接涉及TLS配置,但建议在部署层面确保:
第一,所有API必须通过HTTPS访问,禁用HTTP明文传输。第二,配置TLS 1.2或更高版本,禁用不安全的加密套件。第三,实施HSTS(HTTP Strict Transport Security)头,防止协议降级攻击。第四,定期更新SSL证书,实施证书轮换机制。
六、数据库安全评估
6.1 数据库访问控制
系统使用SeaORM框架与MySQL数据库交互,但当前代码中数据库连接配置直接硬编码在代码中(第12行):
pub struct Config {
pub database_url: String,
// 其他配置...
}
这是严重的安全风险。数据库连接信息(包括用户名、密码)不应硬编码在代码中。建议使用以下方式管理数据库凭据:第一,使用环境变量或配置服务存储数据库凭据;第二,实施数据库用户的最小权限原则,不同应用使用不同账户;第三,定期轮换数据库密码,遵循密码复杂度要求。
6.2 数据库权限配置
建议按照最小权限原则配置数据库用户权限:
-- 应用数据库用户权限(仅生产环境使用)
CREATE USER 'bank_app'@'%' IDENTIFIED BY 'complex_password_here';
GRANT SELECT, INSERT, UPDATE, DELETE ON bank_go.* TO 'bank_app'@'%';
-- 禁止DDL权限(CREATE, ALTER, DROP)
-- 禁止GRANT权限
6.3 SQL注入防护
系统使用SeaORM的查询构建器,天然具备SQL注入防护能力。但仍需注意以下情况:
第一,避免使用字符串拼接构建SQL查询:
// 不安全:字符串拼接
let query = format!("SELECT * FROM account WHERE id = {}", account_id);
// 安全:使用参数化查询
Account::find_by_id(account_id).all(&db).await;
第二,谨慎使用sea_strorage::RawValue或原生SQL查询,确保参数正确绑定。
6.4 敏感数据加密
数据库中存储的敏感数据应当加密:
// 字段级加密示例
#[derive(Clone, Deserialize, Serialize)]
pub struct EncryptedField {
pub encrypted_data: Vec<u8>, // 加密后的数据
pub iv: Vec<u8>, // 初始化向量
pub algorithm: String, // 加密算法
}
// 使用AES-256-GCM进行加密
建议对以下字段进行数据库层加密:银行卡号、身份证号、联系方式、支付密码、安全问题答案。
6.5 数据备份与恢复
建议配置数据库的定期备份和恢复机制:
第一,每日全量备份,每小时增量备份。第二,备份数据加密存储,备份介质异地保管。第三,定期进行恢复演练,验证备份的可用性。第四,实施备份保留策略,满足监管要求的日志保存期限。
七、密钥与凭证管理评估
7.1 密钥管理现状
通过代码审查,我们发现系统缺少专用的密钥管理机制。敏感信息(如数据库密码、银行API密钥)目前通过配置文件管理,存在以下风险:
第一,配置文件可能被提交到版本控制系统,导致密钥泄露。第二,配置文件可能被部署人员不当访问,造成密钥泄露。第三,缺少密钥轮换机制,长期使用的密钥可能被暴力破解。
7.2 密钥管理建议
建议实施以下密钥管理措施:
第一,使用专用的密钥管理服务:
// 使用HashiCorp Vault示例
pub async fn get_secret(path: &str) -> Result<SecretResponse> {
let client = VaultClient::new().await?;
client.read(path).await
}
// 或使用AWS KMS
pub async fn decrypt_data(encrypted: &[u8]) -> Result<Vec<u8>> {
let kms = KmsClient::new(Region::CnNorth1).await?;
let decrypt_output = kms.decrypt(DecryptRequest {
ciphertext_blob: encrypted.to_vec(),
..Default::default()
}).await?;
Ok(decrypt_output.plaintext)
}
第二,实施密钥轮换机制:
// 密钥轮换策略
pub struct KeyRotationPolicy {
pub database_password_rotation_days: 90,
pub api_key_rotation_days: 180,
pub encryption_key_rotation_days: 365,
}
第三,禁用硬编码密钥:
// 在代码中移除所有硬编码的密钥
// BAD: const API_KEY: &str = "sk-test-12345";
// GOOD: let api_key = std::env::var("API_KEY")?;
八、日志与监控安全评估
8.1 日志安全
系统使用tracing库进行日志记录,但当前实现存在以下问题:
第一,日志级别配置可能暴露敏感信息。在开发环境中,debug级别的日志可能包含详细的请求参数和响应数据。第二,日志文件存储在应用服务器本地,可能被未授权访问。第三,缺少日志的完整性校验机制。
建议实施以下日志安全措施:
// 日志脱敏中间件
async fn logging_middleware<B>(mut req: Request<B>, next: Next<B>) -> Response {
let sanitized_request = sanitize_request(&req);
let response = next.run(req).await;
// 记录脱敏后的请求信息
tracing::info!("Request: {:?}", sanitized_request);
response
}
// 日志文件权限控制
// - 设置日志文件权限为600(仅应用用户可读写)
// - 日志目录权限为700(仅应用用户可访问)
8.2 安全监控
建议增加以下安全监控能力:
第一,异常登录监控。监控失败的登录尝试,识别暴力破解攻击。第二,敏感操作告警。对大额交易、账户变更等敏感操作配置实时告警。第三,API异常监控。监控异常的API调用模式,如请求频率突增、异常时间访问等。第四,系统完整性监控。监控系统文件的变更,检测潜在的入侵行为。
// 安全告警配置
pub struct SecurityAlertConfig {
pub failed_login_threshold: u32, // 失败登录阈值
pub failed_login_window_seconds: u32, // 时间窗口
pub large_transaction_amount: Decimal, // 大额交易阈值
pub account_change_alert: bool, // 账户变更告警
pub enable_rate_limit_alert: bool, // 速率限制告警
}
九、发现的问题与改进建议
9.1 高优先级问题
问题一:缺少身份认证机制
所有API端点当前都是开放的,任何人可以访问系统的全部功能。这是严重的安全漏洞,必须立即修复。
建议改进:集成JWT认证机制,验证每个请求的合法性;实现基于角色的访问控制;配置API网关进行统一的认证处理;在上线前进行安全测试,验证认证机制的有效性。
问题二:审计日志不完整
系统当前的日志仅记录业务操作,未记录用户操作审计,缺少操作人标识和完整的操作轨迹。
建议改进:实现完整的审计日志框架,记录所有关键操作;增加操作人、IP地址、操作时间等审计字段;使用独立的审计日志存储,确保日志不可篡改;实现审计日志的完整性校验机制。
问题三:数据库凭据管理不安全
数据库连接信息硬编码在配置中,未使用密钥管理服务,存在凭据泄露风险。
建议改进:使用环境变量或密钥管理服务存储数据库凭据;实施数据库用户的最小权限原则;定期轮换数据库密码;检查版本控制系统,确保凭据未泄露。
9.2 中优先级问题
问题四:敏感数据保护不足
错误信息和API响应中可能泄露敏感数据,如账户余额、交易明细等。
建议改进:对错误信息进行脱敏处理;实现API响应的敏感字段脱敏;数据库层面对敏感字段进行加密存储;增加敏感数据访问的审计日志。
问题五:缺少API安全控制
未实现请求速率限制、输入验证等API安全控制。
建议改进:实现API速率限制,防止暴力破解和DDoS攻击;实施完整的输入验证,防止注入攻击;禁用敏感信息泄露,配置安全的错误响应;实现API调用的完整日志记录。
问题六:缺少安全监控和告警
未实现异常登录监控、敏感操作告警等安全监控能力。
建议改进:实现异常登录监控和告警;配置敏感操作的实时告警;实现API异常监控和告警;部署入侵检测系统。
9.3 低优先级问题
问题七:密钥轮换机制缺失
长期使用的密钥可能被暴力破解,缺少密钥轮换机制。
建议改进:实施密钥轮换策略,定期更换敏感密钥;使用密钥管理服务简化密钥轮换;监控密钥使用情况,识别异常访问。
问题八:日志存储不安全
日志文件存储在应用服务器本地,可能被未授权访问或篡改。
建议改进:配置日志文件权限为最小权限;实现日志的远程存储;增加日志完整性校验;配置日志保留策略,满足监管要求。
问题九:依赖项安全风险
系统使用的第三方依赖可能存在已知的安全漏洞。
建议改进:使用cargo audit定期检查依赖项漏洞;更新到依赖项的稳定版本;移除未使用的依赖项;监控依赖项的安全公告。
十、结论与建议总结
10.1 总体评价
经过全面的安全审计,我们认为该银行系统在安全方面存在较多高优先级风险。最严重的问题是缺少身份认证机制,这意味着系统当前状态不适合直接部署到生产环境。
系统的其他安全机制(如日志记录、错误处理)基本规范,但缺乏身份认证、访问控制、完整审计日志等核心安全能力,需要进行系统性加固。
10.2 优先改进建议
第一,立即实现身份认证机制。这是所有安全改进的基础,建议在上线前完成JWT认证和RBAC授权的实现。
第二,完善审计日志能力。实现完整的用户操作审计,记录操作人、时间、内容、结果等信息。使用独立的审计日志存储,确保日志不可篡改。
第三,加强敏感数据保护。对敏感数据进行脱敏处理和加密存储,在API响应中实施统一的数据保护措施。
第四,建立安全监控体系。实现异常登录监控、敏感操作告警、API异常监控等安全监控能力。
第五,完善密钥管理机制。使用密钥管理服务存储敏感凭据,实施密钥轮换策略。
10.3 安全合规建议
建议在系统上线前完成以下合规准备工作:
第一,进行网络安全等级保护测评,确保系统满足等级保护要求。第二,开展渗透测试,由专业安全团队测试系统的安全性。第三,制定安全运营制度,包括安全事件响应流程、漏洞管理流程等。第四,完成安全培训,确保开发团队具备安全开发意识。
10.4 安全改进优先级
本次安全审计共发现问题9项,按优先级整理如下:
短期(上线前必须解决):身份认证机制、审计日志不完整、数据库凭据管理不安全、敏感数据保护不足。
中期(上线后1至2个月解决):API安全控制缺失、安全监控和告警缺失、密钥轮换机制缺失。
长期(持续改进):日志存储不安全、依赖项安全风险。
报告编制:安全审计专家团队
报告日期:2026年1月6日
审核范围:身份认证、访问控制、数据保护、审计日志、API安全