返回 筑基・数据元府藏真

数据库安全与合规

博主
大约 16 分钟

数据库安全与合规

一、问题引入:数据泄露危机

1.1 真实案例:用户信息泄露事件

事故时间:2024年3月
事故场景:某电商平台用户数据泄露,涉及500万用户信息

攻击路径分析:
┌─────────────────────────────────────────────────────────────┐
│ T1 攻击者通过SQL注入获取数据库访问权限                        │
│     - 利用订单查询接口的注入漏洞                              │
│     - 注入 payload:' UNION SELECT * FROM user--            │
│                                                             │
│ T2 提升权限,获取敏感数据                                     │
│     - 发现应用账号具有DBA权限                                 │
│     - 直接导出user表所有数据                                  │
│                                                             │
│ T3 数据在暗网出售                                             │
│     - 包含:手机号、地址、身份证号                            │
│     - 部分用户密码明文存储                                    │
│                                                             │
│ 后果:                                                      │
│ - 监管罚款:200万元(违反个人信息保护法)                     │
│ - 品牌损失:用户信任度下降,流失15%                           │
│ - 法律风险:面临集体诉讼                                      │
│ - 整改成本:安全体系重建,花费500万                           │
└─────────────────────────────────────────────────────────────┘

安全漏洞复盘:
1. 应用存在SQL注入漏洞
2. 数据库账号权限过大
3. 敏感数据未加密存储
4. 缺少审计日志
5. 没有数据脱敏机制
6. 安全补丁未及时更新

整改措施:
1. 全面代码审计,修复注入漏洞
2. 实施最小权限原则
3. 敏感字段加密存储
4. 部署数据库审计系统
5. 数据脱敏展示
6. 建立安全更新流程

1.2 数据库安全威胁全景

数据库面临的威胁:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  外部威胁                                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ • SQL注入攻击                                          │   │
│  │ • 暴力破解密码                                         │   │
│  │ • 网络嗅探                                             │   │
│  │ • 勒索软件加密                                         │   │
│  │ • DDoS攻击                                             │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
│  内部威胁                                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ • 越权访问                                             │   │
│  │ • 数据窃取                                             │   │
│  │ • 误操作                                               │   │
│  │ • 账号共享                                             │   │
│  │ • 离职人员权限未回收                                   │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
│  系统漏洞                                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ • 数据库软件漏洞                                       │   │
│  │ • 操作系统漏洞                                         │   │
│  │ • 配置错误                                             │   │
│  │ • 默认密码                                             │   │
│  │ • 未加密传输                                           │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
└──────────────────────────────────────────────────────────────┘

二、访问控制与权限管理

2.1 最小权限原则

-- 1. 创建应用专用账号(禁止DDL权限)
CREATE USER 'app_readonly'@'10.0.%.%' IDENTIFIED BY 'ComplexP@ssw0rd123!';
CREATE USER 'app_readwrite'@'10.0.%.%' IDENTIFIED BY 'ComplexP@ssw0rd456!';
CREATE USER 'app_admin'@'10.0.%.%' IDENTIFIED BY 'ComplexP@ssw0rd789!';

-- 2. 只读账号 - 报表查询、数据分析
GRANT SELECT ON mydb.orders TO 'app_readonly'@'10.0.%.%';
GRANT SELECT ON mydb.products TO 'app_readonly'@'10.0.%.%';

-- 3. 读写账号 - 业务应用
GRANT SELECT, INSERT, UPDATE ON mydb.orders TO 'app_readwrite'@'10.0.%.%';
GRANT SELECT, INSERT, UPDATE ON mydb.order_items TO 'app_readwrite'@'10.0.%.%';
GRANT SELECT ON mydb.products TO 'app_readwrite'@'10.0.%.%';
-- 明确禁止DELETE权限
REVOKE DELETE ON mydb.* FROM 'app_readwrite'@'10.0.%.%';

-- 4. 管理账号 - 运维使用(限制IP)
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX ON mydb.* 
TO 'app_admin'@'10.0.1.10';

-- 5. 禁止危险权限
REVOKE ALL PRIVILEGES ON *.* FROM 'app_admin'@'10.0.1.10';
REVOKE GRANT OPTION ON *.* FROM 'app_admin'@'10.0.1.10';
REVOKE FILE ON *.* FROM 'app_admin'@'10.0.1.10';
REVOKE SUPER ON *.* FROM 'app_admin'@'10.0.1.10';

-- 6. 查看权限
SHOW GRANTS FOR 'app_readwrite'@'10.0.%.%';

-- 7. 定期审计权限
SELECT user, host, db, select_priv, insert_priv, update_priv, delete_priv
FROM mysql.db WHERE db = 'mydb';

-- 8. 回收离职人员权限
REVOKE ALL PRIVILEGES ON *.* FROM 'old_employee'@'%';
DROP USER 'old_employee'@'%';

2.2 账号生命周期管理

-- 1. 密码策略配置
SET GLOBAL validate_password.policy = STRONG;
SET GLOBAL validate_password.length = 12;
SET GLOBAL validate_password.mixed_case_count = 1;
SET GLOBAL validate_password.number_count = 1;
SET GLOBAL validate_password.special_char_count = 1;

-- 2. 密码过期策略
ALTER USER 'app_readwrite'@'10.0.%.%' PASSWORD EXPIRE INTERVAL 90 DAY;

-- 3. 登录失败锁定
INSTALL PLUGIN CONNECTION_CONTROL SONAME 'connection_control.so';
INSTALL PLUGIN CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS SONAME 'connection_control.so';

SET GLOBAL connection_control_failed_connections_threshold = 5;
SET GLOBAL connection_control_min_connection_delay = 1000;
SET GLOBAL connection_control_max_connection_delay = 20000;

-- 4. 空闲会话超时
SET GLOBAL wait_timeout = 3600;  -- 1小时
SET GLOBAL interactive_timeout = 3600;

-- 5. 创建临时账号(带过期时间)
CREATE USER 'temp_developer'@'10.0.1.%' IDENTIFIED BY 'TempP@ss123!'
PASSWORD EXPIRE INTERVAL 7 DAY;
GRANT SELECT ON mydb.* TO 'temp_developer'@'10.0.1.%';

-- 6. 定期清理无效账号
SELECT user, host, password_last_changed, password_lifetime
FROM mysql.user 
WHERE password_last_changed < DATE_SUB(NOW(), INTERVAL 1 YEAR);

三、数据加密

3.1 传输加密(SSL/TLS)

# 1. 生成SSL证书
mkdir -p /etc/mysql/ssl
cd /etc/mysql/ssl

# 生成CA证书
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca-cert.pem \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=MySQL-CA"

# 生成服务器证书
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-req.pem \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=mysql.server.com"
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem \
    -set_serial 01 -out server-cert.pem

# 生成客户端证书
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -out client-req.pem \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=mysql.client.com"
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem \
    -set_serial 01 -out client-cert.pem

# 设置权限
chown -R mysql:mysql /etc/mysql/ssl
chmod 600 /etc/mysql/ssl/*.pem
# my.cnf SSL配置
[mysqld]
# 强制SSL连接
require_secure_transport = ON

# SSL证书路径
ssl-ca=/etc/mysql/ssl/ca-cert.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem

# 加密连接参数
tls_version=TLSv1.2,TLSv1.3
ssl_cipher=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256

# 客户端配置
[client]
ssl-ca=/etc/mysql/ssl/ca-cert.pem
ssl-cert=/etc/mysql/ssl/client-cert.pem
ssl-key=/etc/mysql/ssl/client-key.pem
ssl-mode=VERIFY_CA
-- 验证SSL连接
SHOW VARIABLES LIKE '%ssl%';
SHOW STATUS LIKE 'Ssl_cipher';

-- 查看当前连接是否使用SSL
SELECT id, user, host, ssl_type, ssl_cipher 
FROM information_schema.processlist 
WHERE ssl_type IS NOT NULL;

-- 创建强制SSL的用户
CREATE USER 'secure_user'@'%' REQUIRE SSL;
CREATE USER 'secure_user'@'%' REQUIRE X509;  -- 需要客户端证书

3.2 存储加密(TDE)

-- MySQL 8.0 TDE配置

-- 1. 安装keyring插件
INSTALL PLUGIN keyring_file SONAME 'keyring_file.so';

-- 2. 配置keyring
SET GLOBAL keyring_file_data = '/var/lib/mysql-keyring/keyring';

-- 3. 创建加密表空间
CREATE TABLESPACE encrypted_ts
ADD DATAFILE 'encrypted_ts.ibd'
ENCRYPTION='Y';

-- 4. 创建加密表
CREATE TABLE sensitive_data (
    id INT PRIMARY KEY,
    ssn VARCHAR(20),
    credit_card VARCHAR(20)
) ENCRYPTION='Y';

-- 5. 对现有表启用加密
ALTER TABLE orders ENCRYPTION='Y';

-- 6. 查看加密状态
SELECT TABLE_NAME, TABLE_SCHEMA, CREATE_OPTIONS 
FROM information_schema.TABLES 
WHERE CREATE_OPTIONS LIKE '%ENCRYPTION%'
   OR TABLESPACE_NAME IN (SELECT TABLESPACE_NAME 
                          FROM information_schema.INNODB_TABLESPACES 
                          WHERE ENCRYPTION='Y');

-- 7. 轮换加密密钥(定期执行)
ALTER INSTANCE ROTATE INNODB MASTER KEY;

3.3 应用层加密

/**
 * 敏感数据加密服务
 */
@Service
public class EncryptionService {
    
    @Value("${encryption.key}")
    private String encryptionKey;
    
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final int GCM_IV_LENGTH = 12;
    private static final int GCM_TAG_LENGTH = 16;
    
    /**
     * 加密敏感字段
     */
    public String encrypt(String plaintext) {
        if (plaintext == null || plaintext.isEmpty()) {
            return plaintext;
        }
        
        try {
            byte[] iv = new byte[GCM_IV_LENGTH];
            SecureRandom random = new SecureRandom();
            random.nextBytes(iv);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            SecretKeySpec keySpec = new SecretKeySpec(encryptionKey.getBytes(StandardCharsets.UTF_8), "AES");
            
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, parameterSpec);
            byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
            
            // 组合IV和密文
            byte[] combined = new byte[iv.length + encrypted.length];
            System.arraycopy(iv, 0, combined, 0, iv.length);
            System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
            
            return Base64.getEncoder().encodeToString(combined);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }
    
    /**
     * 解密敏感字段
     */
    public String decrypt(String ciphertext) {
        if (ciphertext == null || ciphertext.isEmpty()) {
            return ciphertext;
        }
        
        try {
            byte[] combined = Base64.getDecoder().decode(ciphertext);
            
            byte[] iv = new byte[GCM_IV_LENGTH];
            byte[] encrypted = new byte[combined.length - GCM_IV_LENGTH];
            System.arraycopy(combined, 0, iv, 0, iv.length);
            System.arraycopy(combined, iv.length, encrypted, 0, encrypted.length);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            SecretKeySpec keySpec = new SecretKeySpec(encryptionKey.getBytes(StandardCharsets.UTF_8), "AES");
            
            cipher.init(Cipher.DECRYPT_MODE, keySpec, parameterSpec);
            byte[] decrypted = cipher.doFinal(encrypted);
            
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }
    
    /**
     * 哈希敏感数据(用于查询)
     */
    public String hash(String input) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(hash);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("哈希失败", e);
        }
    }
}

/**
 * 加密字段的JPA转换器
 */
@Converter
public class EncryptedAttributeConverter implements AttributeConverter<String, String> {
    
    @Autowired
    private EncryptionService encryptionService;
    
    @Override
    public String convertToDatabaseColumn(String attribute) {
        return encryptionService.encrypt(attribute);
    }
    
    @Override
    public String convertToEntityAttribute(String dbData) {
        return encryptionService.decrypt(dbData);
    }
}

/**
 * 用户实体(使用加密)
 */
@Entity
@Table(name = "user")
public class User {
    
    @Id
    private Long id;
    
    private String username;
    
    // 手机号加密存储
    @Convert(converter = EncryptedAttributeConverter.class)
    @Column(name = "phone_encrypted")
    private String phone;
    
    // 手机号哈希(用于查询)
    @Column(name = "phone_hash")
    private String phoneHash;
    
    // 身份证号加密
    @Convert(converter = EncryptedAttributeConverter.class)
    private String idCard;
    
    // 设置手机号时同时设置哈希
    public void setPhone(String phone) {
        this.phone = phone;
        this.phoneHash = encryptionService.hash(phone);
    }
}

四、SQL注入防护

4.1 参数化查询

/**
 * SQL注入防护示例
 */
@Repository
public class UserRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    /**
     * ❌ 错误:字符串拼接SQL
     */
    public User findByUsernameUnsafe(String username) {
        // 危险!存在SQL注入
        String sql = "SELECT * FROM user WHERE username = '" + username + "'";
        // 攻击者可以传入:' OR '1'='1
        return jdbcTemplate.queryForObject(sql, User.class);
    }
    
    /**
     * ✅ 正确:使用参数化查询
     */
    public User findByUsernameSafe(String username) {
        String sql = "SELECT * FROM user WHERE username = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{username}, User.class);
    }
    
    /**
     * ✅ 正确:使用NamedParameterJdbcTemplate
     */
    public User findByUsernameNamed(String username) {
        String sql = "SELECT * FROM user WHERE username = :username";
        Map<String, Object> params = new HashMap<>();
        params.put("username", username);
        return namedParameterJdbcTemplate.queryForObject(sql, params, User.class);
    }
}

/**
 * MyBatis参数化
 */
@Mapper
public interface UserMapper {
    
    // ✅ 正确:使用#{}占位符(预编译)
    @Select("SELECT * FROM user WHERE username = #{username}")
    User findByUsername(@Param("username") String username);
    
    // ❌ 错误:使用${}字符串替换(有注入风险)
    @Select("SELECT * FROM ${tableName} WHERE id = #{id}")
    User findByIdUnsafe(@Param("tableName") String tableName, @Param("id") Long id);
    
    // ✅ 正确:动态SQL使用安全方式
    @Select("<script>" +
            "SELECT * FROM user " +
            "<where>" +
            "  <if test='username != null'> AND username = #{username} </if>" +
            "  <if test='email != null'> AND email = #{email} </if>" +
            "</where>" +
            "</script>")
    List<User> findByCondition(@Param("username") String username, 
                                @Param("email") String email);
}

4.2 输入验证与过滤

/**
 * 输入验证服务
 */
@Component
public class InputValidationService {
    
    // SQL关键字黑名单
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
        "('|\"|;|--|/\\*|\\*/|union|select|insert|update|delete|drop|create|alter|exec|execute|xp_|sp_)",
        Pattern.CASE_INSENSITIVE
    );
    
    /**
     * 验证输入是否安全
     */
    public boolean isSafe(String input) {
        if (input == null || input.isEmpty()) {
            return true;
        }
        return !SQL_INJECTION_PATTERN.matcher(input).find();
    }
    
    /**
     * 清理危险字符
     */
    public String sanitize(String input) {
        if (input == null) {
            return null;
        }
        return input.replaceAll("['\";\\-\\/]", "");
    }
    
    /**
     * 验证排序字段(防止注入)
     */
    public String validateOrderBy(String orderBy) {
        Set<String> allowedColumns = Set.of("id", "username", "created_at", "updated_at");
        Set<String> allowedDirections = Set.of("ASC", "DESC");
        
        String[] parts = orderBy.split("\\s+");
        String column = parts[0];
        String direction = parts.length > 1 ? parts[1].toUpperCase() : "ASC";
        
        if (!allowedColumns.contains(column) || !allowedDirections.contains(direction)) {
            throw new IllegalArgumentException("Invalid order by clause");
        }
        
        return column + " " + direction;
    }
}

五、审计与监控

5.1 数据库审计

-- MySQL审计插件配置

-- 1. 安装审计插件
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

-- 2. 配置审计策略
SET GLOBAL audit_log_policy = 'ALL';  -- ALL, LOGINS, QUERIES, NONE
SET GLOBAL audit_log_format = 'JSON';
SET GLOBAL audit_log_file = '/var/lib/mysql/audit.log';

-- 3. 审计特定表
SET GLOBAL audit_log_include_accounts = 'app_user@%,admin@%';
SET GLOBAL audit_log_exclude_accounts = 'monitor@%,backup@%';

-- 4. 查看审计日志
SELECT * FROM mysql.audit_log ORDER BY timestamp DESC LIMIT 100;

-- 5. 查询敏感操作
SELECT * FROM mysql.audit_log 
WHERE command_class IN ('drop_table', 'delete', 'update')
  AND timestamp > DATE_SUB(NOW(), INTERVAL 1 DAY);
/**
 * 数据库操作审计
 */
@Aspect
@Component
@Slf4j
public class DatabaseAuditAspect {
    
    @Autowired
    private AuditLogRepository auditLogRepository;
    
    @Around("@annotation(auditable)")
    public Object audit(ProceedingJoinPoint joinPoint, Auditable auditable) throws Throwable {
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        String operation = auditable.operation();
        String table = auditable.table();
        
        AuditLog auditLog = new AuditLog();
        auditLog.setUsername(username);
        auditLog.setOperation(operation);
        auditLog.setTableName(table);
        auditLog.setRequestTime(LocalDateTime.now());
        auditLog.setIpAddress(getClientIp());
        
        try {
            Object result = joinPoint.proceed();
            auditLog.setStatus("SUCCESS");
            return result;
        } catch (Exception e) {
            auditLog.setStatus("FAILED");
            auditLog.setErrorMessage(e.getMessage());
            throw e;
        } finally {
            auditLog.setResponseTime(LocalDateTime.now());
            auditLogRepository.save(auditLog);
        }
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Auditable {
    String operation();
    String table();
}

5.2 数据脱敏

/**
 * 数据脱敏服务
 */
@Component
public class DataMaskingService {
    
    /**
     * 手机号脱敏
     */
    public String maskPhone(String phone) {
        if (phone == null || phone.length() != 11) {
            return phone;
        }
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }
    
    /**
     * 身份证号脱敏
     */
    public String maskIdCard(String idCard) {
        if (idCard == null || idCard.length() != 18) {
            return idCard;
        }
        return idCard.substring(0, 6) + "********" + idCard.substring(14);
    }
    
    /**
     * 邮箱脱敏
     */
    public String maskEmail(String email) {
        if (email == null || !email.contains("@")) {
            return email;
        }
        String[] parts = email.split("@");
        String local = parts[0];
        String domain = parts[1];
        
        if (local.length() <= 2) {
            return "*@" + domain;
        }
        return local.substring(0, 2) + "***@" + domain;
    }
    
    /**
     * 银行卡号脱敏
     */
    public String maskBankCard(String cardNo) {
        if (cardNo == null || cardNo.length() < 8) {
            return cardNo;
        }
        return cardNo.substring(0, 4) + " **** **** " + cardNo.substring(cardNo.length() - 4);
    }
    
    /**
     * 姓名脱敏
     */
    public String maskName(String name) {
        if (name == null || name.isEmpty()) {
            return name;
        }
        if (name.length() == 2) {
            return "*" + name.substring(1);
        }
        return name.charAt(0) + "*" + name.substring(name.length() - 1);
    }
}

/**
 * 脱敏JSON序列化器
 */
public class MaskingSerializer extends JsonSerializer<String> {
    
    private final MaskingType type;
    
    public MaskingSerializer(MaskingType type) {
        this.type = type;
    }
    
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) 
            throws IOException {
        DataMaskingService maskingService = SpringContextUtil.getBean(DataMaskingService.class);
        
        String masked = switch (type) {
            case PHONE -> maskingService.maskPhone(value);
            case ID_CARD -> maskingService.maskIdCard(value);
            case EMAIL -> maskingService.maskEmail(value);
            case BANK_CARD -> maskingService.maskBankCard(value);
            case NAME -> maskingService.maskName(value);
            default -> value;
        };
        
        gen.writeString(masked);
    }
}

// 使用示例
public class UserDTO {
    private String username;
    
    @JsonSerialize(using = MaskingSerializer.class)
    @MaskingType(MaskingType.PHONE)
    private String phone;
    
    @JsonSerialize(using = MaskingSerializer.class)
    @MaskingType(MaskingType.ID_CARD)
    private String idCard;
}

六、合规要求

6.1 等保2.0要求

等保2.0(三级)数据库安全要求:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  身份鉴别                                                    │
│  - 使用双因素认证                                            │
│  - 密码复杂度要求                                            │
│  - 登录失败锁定                                              │
│  - 会话超时                                                  │
│                                                              │
│  访问控制                                                    │
│  - 最小权限原则                                              │
│  - 敏感数据分级                                              │
│  - 操作审批流程                                              │
│                                                              │
│  安全审计                                                    │
│  - 启用审计日志                                              │
│  - 审计记录留存6个月以上                                     │
│  - 审计记录防篡改                                            │
│                                                              │
│  数据完整性                                                  │
│  - 传输完整性校验                                            │
│  - 存储完整性保护                                            │
│                                                              │
│  数据保密性                                                  │
│  - 传输加密(TLS)                                           │
│  - 存储加密(TDE)                                           │
│  - 敏感数据脱敏                                              │
│                                                              │
│  数据备份恢复                                                │
│  - 定期备份                                                  │
│  - 异地备份                                                  │
│  - 恢复演练                                                  │
│                                                              │
└──────────────────────────────────────────────────────────────┘

6.2 个人信息保护法合规

个人信息保护法要求:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  数据收集                                                    │
│  - 明确告知收集目的                                          │
│  - 获得用户同意                                              │
│  - 最小必要原则                                              │
│                                                              │
│  数据存储                                                    │
│  - 敏感信息加密存储                                          │
│  - 去标识化处理                                              │
│  - 访问日志记录                                              │
│                                                              │
│  数据使用                                                    │
│  - 不超范围使用                                              │
│  - 不非法提供给他人                                          │
│  - 自动化决策透明                                            │
│                                                              │
│  数据安全                                                    │
│  - 制定内部管理制度                                          │
│  - 采取技术保护措施                                          │
│  - 定期安全培训                                              │
│                                                              │
│  数据删除                                                    │
│  - 用户要求时及时删除                                        │
│  - 服务终止时删除                                            │
│  - 留存期满时删除                                            │
│                                                              │
└──────────────────────────────────────────────────────────────┘

七、安全最佳实践清单

┌─────────────────────────────────────────────────────────────────────┐
│                      数据库安全最佳实践清单                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  【账号安全】                                                       │
│  □ 1. 实施最小权限原则                                             │
│  □ 2. 定期轮换密码(90天)                                         │
│  □ 3. 启用登录失败锁定                                             │
│  □ 4. 删除默认账号(如root@%)                                     │
│  □ 5. 定期审计账号权限                                             │
│                                                                     │
│  【网络安全】                                                       │
│  □ 1. 强制SSL/TLS加密连接                                          │
│  □ 2. 限制数据库访问IP                                             │
│  □ 3. 使用防火墙隔离数据库                                         │
│  □ 4. 关闭不必要的端口                                             │
│                                                                     │
│  【数据安全】                                                       │
│  □ 1. 敏感数据加密存储                                             │
│  □ 2. 敏感数据脱敏展示                                             │
│  □ 3. 使用参数化查询防注入                                         │
│  □ 4. 启用数据库审计                                               │
│                                                                     │
│  【运维安全】                                                       │
│  □ 1. 及时更新安全补丁                                             │
│  □ 2. 定期安全扫描                                                 │
│  □ 3. 制定灾难恢复预案                                             │
│  □ 4. 定期安全培训                                                 │
│                                                                     │
│  【合规要求】                                                       │
│  □ 1. 满足等保要求                                                 │
│  □ 2. 个人信息保护合规                                             │
│  □ 3. 审计日志留存6个月以上                                        │
│  □ 4. 定期合规检查                                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

系列上一篇备份恢复与灾难恢复策略

系列总结

本系列从数据库选型、设计、优化、架构、高级特性到运维安全,构建了完整的数据库知识体系。掌握这些知识,可以应对从单机到分布式、从开发到生产的各种数据库挑战。

知识点测试

读完文章了?来测试一下你对知识点的掌握程度吧!

评论区

使用 GitHub 账号登录后即可发表评论,支持 Markdown 格式。

如果评论系统无法加载,请确保:

  • 您的网络可以访问 GitHub
  • giscus GitHub App 已安装到仓库
  • 仓库已启用 Discussions 功能