-- ============================================================ -- 安全设备 Demo - 数据库初始化脚本 -- 库名: secure_device (与 application.properties 中配置一致) -- 说明: 存储照片元数据、设备、用户 -- 密文本身落盘于 uploads/ 目录 -- 服务端永远不存明文照片和明文 DEK -- ============================================================ -- 1. 创建数据库(如已存在可跳过) CREATE DATABASE IF NOT EXISTS `secure_device` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE `secure_device`; -- 2. 加密照片表(对应 EncryptedPhoto 实体) CREATE TABLE IF NOT EXISTS `encrypted_photo` ( `photo_id` VARCHAR(64) NOT NULL COMMENT '照片唯一 ID (PK)', `device_id` VARCHAR(64) DEFAULT NULL COMMENT '来源设备 ID', `user_id` VARCHAR(64) DEFAULT NULL COMMENT '所属用户 ID', `file_path` VARCHAR(512) DEFAULT NULL COMMENT '密文文件落盘路径', `iv_base64` VARCHAR(256) DEFAULT NULL COMMENT 'GCM IV (Base64)', `encrypted_dek_base64` VARCHAR(1024) DEFAULT NULL COMMENT 'DEK 被 UK 加密后的密文 (Base64)', `metadata_signature` VARCHAR(1024) DEFAULT NULL COMMENT '设备私钥签名 (Base64)', `upload_time` BIGINT DEFAULT NULL COMMENT '上传时间戳 (ms)', PRIMARY KEY (`photo_id`), KEY `idx_user_id` (`user_id`), KEY `idx_device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='加密照片元数据表'; -- 3. 设备表(对应 Device 实体) CREATE TABLE IF NOT EXISTS `device` ( `device_id` VARCHAR(64) NOT NULL COMMENT '设备唯一 ID (UUID, PK)', `sn` VARCHAR(64) NOT NULL COMMENT '设备序列号 (唯一)', `user_id` VARCHAR(64) DEFAULT NULL COMMENT '绑定的用户 ID', `public_key_base64` TEXT DEFAULT NULL COMMENT '设备 TEE 公钥 (Base64)', `bind_time` BIGINT DEFAULT NULL COMMENT '绑定时间戳 (ms)', `last_recovery_time` BIGINT DEFAULT NULL COMMENT '最近一次恢复时间戳 (ms)', `active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否激活 (1 激活 / 0 停用)', PRIMARY KEY (`device_id`), KEY `idx_device_sn` (`sn`), KEY `idx_device_user` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='设备注册与绑定状态表(一个 SN 可有多条历史记录,仅一条 active)'; -- 4. 用户表(对应 User 实体) CREATE TABLE IF NOT EXISTS `app_user` ( `user_id` VARCHAR(64) NOT NULL COMMENT '用户 ID (PK)', `phone` VARCHAR(32) DEFAULT NULL COMMENT '手机号(用于短信验证)', `uk_encrypted_base64` TEXT DEFAULT NULL COMMENT '用户主密钥 UK(经 SMK-AES-256-GCM 信封加密,格式 ivBase64:ciphertextBase64,非明文)', `password` VARCHAR(128) DEFAULT NULL COMMENT '登录密码 (BCrypt 哈希,60 字符,绝不明文)', `phone_verified` VARCHAR(8) DEFAULT NULL COMMENT '手机号是否已验证', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户与主密钥表'; -- ============================================================ -- 已有数据库迁移(仅当旧库的 device 表带 SN 唯一索引时手动执行) -- 说明:早期版本 device.sn 建为 UNIQUE 索引,导致「恢复出厂重新注册」时 -- 报 Duplicate entry。现将 SN 改为普通索引(一个 SN 可有多条历史设备记录, -- 仅一条 active)。spring.jpa.hibernate.ddl-auto=update 不会自动删除已存在 -- 的唯一索引,故需手动执行下面两句: -- ============================================================ -- ALTER TABLE `device` DROP INDEX `idx_device_sn`; -- ALTER TABLE `device` ADD INDEX `idx_device_sn` (`sn`); -- ============================================================ -- 迁移:P0-1 修复(UK 明文落库 -> SMK 信封加密) -- ============================================================ -- 列结构无需变更(uk_encrypted_base64 本就是 TEXT)。 -- 已有旧数据(明文 UK,Base64 且不含冒号)需重新用 SMK 包裹。 -- 纯 SQL 无法完成 AES-256-GCM(密钥来自环境变量 APP_MASTER_KEY), -- 因此由应用侧一次性 Runner 完成: -- -- 设置环境变量后启动应用一次: -- export APP_MASTER_KEY= -- export APP_RUN_MIGRATION=true -- # 启动 Spring Boot,Runner 自动把明文 UK 重新包裹 -- # 成功后关闭:unset APP_RUN_MIGRATION -- -- 若数据库为演示数据、可整体重建,则无需迁移,直接: -- TRUNCATE TABLE `app_user`; -- TRUNCATE TABLE `encrypted_photo`; -- TRUNCATE TABLE `device`; -- 然后重新走注册流程即可(新账号 UK 默认即用 SMK 加密)。 -- 注:早期版本存在 user_photo 关联表(已废弃),照片归属统一由 encrypted_photo.user_id 承担。 -- ============================================================