Skip to content

安全存储

HarmonyOS 提供多种安全存储机制,保护敏感数据如 Token、密码、密钥等。


1. 安全存储方案对比

方案适用场景安全等级API 模块
Preferences普通配置@kit.ArkDataShare
加密 Preferences敏感配置Crypto + Preferences
KeyStore密钥存储@kit.CryptoArchitectureKit
RDB 加密数据库Rdb + 加密
TEE 环境生物特征最高TEE API

2. KeyStore 密钥管理

生成密钥

typescript
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

async function generateKey(): Promise<void> {
  // 创建密钥生成器
  let keyGen = await cryptoFramework.createKeyGen('RSA2048', 'user_id');
  
  // 设置参数
  let param = {
    alias: 'my_key_alias',
    authType: cryptoFramework.AuthType.PIN,
    aesKeyLength: 256
  };
  
  // 生成密钥(存储在 KeyStore)
  await keyGen.generateKey(param);
}

使用密钥加密

typescript
async function encryptData(plainText: string): Promise<string> {
  // 创建加密器
  let encryptor = await cryptoFramework.createEncryptor('AES256', 'user_id');
  
  // 使用 KeyStore 中的密钥加密
  let encrypted = await encryptor.encrypt(plainText, {
    keyAlias: 'my_key_alias'
  });
  
  return encrypted;
}

async function decryptData(cipherText: string): Promise<string> {
  let decryptor = await cryptoFramework.createDecryptor('AES256', 'user_id');
  let decrypted = await decryptor.decrypt(cipherText, {
    keyAlias: 'my_key_alias'
  });
  
  return decrypted;
}

3. 首选项加密存储

加密 Preferences 封装

typescript
import { preferences } from '@kit.ArkDataShare';
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

class SecurePreferences {
  private prefs: preferences.Preferences;
  private encryptor: any;
  private decryptor: any;
  
  constructor(private context: common.Context) {}
  
  async init(): Promise<void> {
    // 初始化加解密器
    this.encryptor = await cryptoFramework.createEncryptor('AES256');
    this.decryptor = await cryptoFramework.createDecryptor('AES256');
    
    // 加载 Preferences
    this.prefs = await preferences.getPreferences(this.context, 'secure_prefs');
  }
  
  async put(key: string, value: string): Promise<void> {
    // 加密后存储
    let encrypted = await this.encryptor.encrypt(value, {
      keyAlias: 'prefs_key'
    });
    await this.prefs.put(key, encrypted);
    await this.prefs.flush();
  }
  
  async get(key: string): Promise<string | null> {
    let encrypted = this.prefs.getSync(key) as string;
    if (!encrypted) return null;
    
    try {
      return await this.decryptor.decrypt(encrypted, {
        keyAlias: 'prefs_key'
      });
    } catch {
      return null;  // 解密失败
    }
  }
  
  async remove(key: string): Promise<void> {
    await this.prefs.delete(key);
    await this.prefs.flush();
  }
}

// 使用
let securePrefs = new SecurePreferences(context);
await securePrefs.init();
await securePrefs.put('auth_token', 'secret_token_123');
let token = await securePrefs.get('auth_token');

4. Token/密码安全存储

Token 存储最佳实践

typescript
class TokenManager {
  private static instance: TokenManager;
  private securePrefs: SecurePreferences;
  
  private constructor(context: common.Context) {
    this.securePrefs = new SecurePreferences(context);
  }
  
  static getInstance(context: common.Context): TokenManager {
    if (!TokenManager.instance) {
      TokenManager.instance = new TokenManager(context);
    }
    return TokenManager.instance;
  }
  
  async saveToken(token: string): Promise<void> {
    // 1. 加密存储
    await this.securePrefs.put('access_token', token);
    
    // 2. 可选:同时存储过期时间
    let expireTime = Date.now() + 7 * 24 * 60 * 60 * 1000;  // 7 天
    await this.securePrefs.put('token_expire', expireTime.toString());
  }
  
  async getToken(): Promise<string | null> {
    // 检查是否过期
    let expireStr = await this.securePrefs.get('token_expire');
    if (expireStr && Date.now() > parseInt(expireStr)) {
      await this.clearToken();
      return null;
    }
    
    return await this.securePrefs.get('access_token');
  }
  
  async clearToken(): Promise<void> {
    await this.securePrefs.remove('access_token');
    await this.securePrefs.remove('token_expire');
  }
}

密码存储(不推荐明文)

typescript
// ❌ 绝对不要明文存储密码
// await prefs.put('password', '123456');

// ✅ 只存储密码哈希或完全不存
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

async function hashPassword(password: string): Promise<string> {
  let digest = await cryptoFramework.createDigest('SHA256');
  return await digest.digest(password);
}

// 验证时使用哈希比对
async function verifyPassword(input: string, storedHash: string): Promise<boolean> {
  let inputHash = await hashPassword(input);
  return inputHash === storedHash;
}

5. 数据库加密

RDB 加密配置

typescript
import { relationalStore } from '@kit.ArkRdb';

async function createEncryptedRdb(): Promise<relationalStore.RdbStore> {
  let config = {
    name: 'secure.db',
    securityLevel: relationalStore.SecurityLevel.SECRECY_LEVEL_HIGH,
    encryptCipher: relationalStore.EncryptCipher.AES_256_GCM
  };
  
  let rdbStore = await relationalStore.getRdbStore(context, config);
  return rdbStore;
}

// 使用加密数据库
let store = await createEncryptedRdb();
await store.insert({
  table: 'users',
  values: {
    'username': 'admin',
    'password_hash': 'hashed_value'
  }
});

6. 生物识别认证

指纹/面部识别

typescript
import { userIAM } from '@kit.UserIAM';

async function authenticateWithBiometrics(): Promise<boolean> {
  let authenticator = userIAM.getAuthenticator(userIAM.AuthType.FINGERPRINT);
  
  let result = await authenticator.authenticate({
    timeout: 60000,  // 60 秒超时
    challenge: 'random_challenge'  // 防止重放攻击
  });
  
  return result.result === userIAM.AuthResult.SUCCESS;
}

// 结合加密
async function secureOperation(): Promise<void> {
  let authenticated = await authenticateWithBiometrics();
  if (!authenticated) {
    throw new Error('生物识别失败');
  }
  
  // 认证通过后才能访问敏感数据
  let token = await TokenManager.getInstance(context).getToken();
}

7. 面试高频问题

Q1: 如何安全存储 Token?

:使用 KeyStore 生成密钥 → 加密 Token → 存储在加密的 Preferences 中 → 定期轮换 Token。

Q2: KeyStore 的作用是什么?

:KeyStore 是系统级的安全密钥存储服务,密钥在 TEE(可信执行环境)中生成和存储,应用无法直接导出。

Q3: 密码应该如何存储?

:永远不要明文存储密码。应该存储密码的哈希值(如 SHA256),验证时比对哈希值。更好的方式是使用 OAuth 等免密码方案。


8. 与 Android 对照

概念HarmonyOSAndroid
KeyStorecryptoFramework.KeyGenKeyStore
加密存储AES256 + PreferencesEncryptedSharedPreferences
生物识别userIAM.AuthenticatorBiometricPrompt
数据库加密RdbStore.securityLevelSQLCipher

面试提示:安全存储是应用安全的核心,需掌握 KeyStore 使用和加密存储方案。