鸿蒙轻松背单词应用开发实战(九)-应用安全与权限管理

前言

应用安全和权限管理是保护用户数据和系统安全的关键。本文详细介绍轻松背单词应用的安全策略和权限管理实现。

为什么需要重视应用安全?

  1. 数据保护:保护用户隐私数据
  2. 权限控制:合理申请和使用权限
  3. 安全防护:防止恶意攻击
  4. 合规要求:满足安全合规标准

应用安全

数据安全

权限管理

网络安全

代码安全

数据加密

数据备份

权限申请

权限检查

HTTPS

证书验证

代码混淆

防篡改

一、权限管理

1.1 权限配置

// module.json5权限配置
{
  "module": {
    "name": "entry",
    "type": "entry",
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "用于同步单词数据",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO",
        "reason": "用于检查网络状态",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.READ_EXTERNAL_STORAGE",
        "reason": "用于导入单词文件",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.WRITE_EXTERNAL_STORAGE",
        "reason": "用于导出学习数据",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

1.2 权限管理器

import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';

export class PermissionManager {
  private static instance: PermissionManager;
  private atManager: abilityAccessCtrl.AccessControlManager;
  
  static getInstance(): PermissionManager {
    if (!PermissionManager.instance) {
      PermissionManager.instance = new PermissionManager();
    }
    return PermissionManager.instance;
  }
  
  constructor() {
    this.atManager = abilityAccessCtrl.createAtManager();
  }
  
  // 检查权限
  async checkPermission(permission: string): Promise<boolean> {
    try {
      const bundleInfo = await bundleManager.getBundleInfoForSelf(
        bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
      );
      
      const grantStatus = await this.atManager.verifyAccessToken(
        bundleInfo.appInfo.accessTokenId,
        permission
      );
      
      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } catch (error) {
      console.error('检查权限失败:', error);
      return false;
    }
  }
  
  // 请求权限
  async requestPermissions(
    context: UIAbilityContext,
    permissions: string[]
  ): Promise<Map<string, boolean>> {
    const results = new Map<string, boolean>();
    
    for (const permission of permissions) {
      const hasPermission = await this.checkPermission(permission);
      
      if (hasPermission) {
        results.set(permission, true);
      } else {
        // 请求权限
        const grantResults = await this.atManager.requestPermissionsFromUser(
          context,
          [permission]
        );
        
        results.set(permission, grantResults.authResults[0] === 0);
      }
    }
    
    return results;
  }
}

1.3 权限使用流程

用户 系统 权限管理器 应用 用户 系统 权限管理器 应用 alt [用户授权] [用户拒绝] alt [权限已授予] [权限未授予] 检查权限 verifyAccessToken 返回权限状态 返回true 执行操作 requestPermissionsFromUser 显示权限对话框 授权/拒绝 返回授权结果 返回授权结果 执行操作 提示用户

二、数据加密

2.1 加密工具类

import cryptoFramework from '@ohos.security.cryptoFramework';

export class CryptoUtil {
  private static instance: CryptoUtil;
  private cipher: cryptoFramework.Cipher | null = null;
  private key: cryptoFramework.SymKey | null = null;
  
  static getInstance(): CryptoUtil {
    if (!CryptoUtil.instance) {
      CryptoUtil.instance = new CryptoUtil();
    }
    return CryptoUtil.instance;
  }
  
  async init(key: string): Promise<void> {
    // 创建AES加密器
    this.cipher = cryptoFramework.createCipher('AES256|ECB|PKCS7');
    
    // 生成密钥
    const keyBlob: cryptoFramework.DataBlob = {
      data: new Uint8Array(Buffer.from(key, 'utf-8').buffer)
    };
    
    const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
    this.key = await symKeyGenerator.convertKey(keyBlob);
    
    // 初始化加密器
    await this.cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, this.key, null);
  }
  
  // 加密数据
  async encrypt(data: string): Promise<string> {
    if (!this.cipher || !this.key) {
      throw new Error('加密器未初始化');
    }
    
    const input: cryptoFramework.DataBlob = {
      data: new Uint8Array(Buffer.from(data, 'utf-8').buffer)
    };
    
    const output = await this.cipher.doFinal(input);
    return Buffer.from(output.data).toString('base64');
  }
  
  // 解密数据
  async decrypt(encryptedData: string): Promise<string> {
    if (!this.cipher || !this.key) {
      throw new Error('加密器未初始化');
    }
    
    // 重新初始化为解密模式
    await this.cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, this.key, null);
    
    const input: cryptoFramework.DataBlob = {
      data: new Uint8Array(Buffer.from(encryptedData, 'base64').buffer)
    };
    
    const output = await this.cipher.doFinal(input);
    return Buffer.from(output.data).toString('utf-8');
  }
}

2.2 安全存储

export class SecureStorage {
  private crypto: CryptoUtil = CryptoUtil.getInstance();
  private preferences: PreferencesUtil = PreferencesUtil.getInstance();
  
  async saveSecureData(key: string, value: string): Promise<void> {
    // 加密数据
    const encryptedValue = await this.crypto.encrypt(value);
    
    // 保存加密数据
    await this.preferences.put(key, encryptedValue);
  }
  
  async getSecureData(key: string): Promise<string | null> {
    // 获取加密数据
    const encryptedValue = await this.preferences.get(key, '');
    
    if (!encryptedValue) {
      return null;
    }
    
    // 解密数据
    return await this.crypto.decrypt(encryptedValue as string);
  }
  
  async removeSecureData(key: string): Promise<void> {
    await this.preferences.delete(key);
  }
}

2.3 数据加密流程

原始数据

数据序列化

加密处理

Base64编码

存储加密数据

读取数据

Base64解码

解密处理

数据反序列化

原始数据

三、网络安全

3.1 HTTPS配置

export class NetworkSecurity {
  private static instance: NetworkSecurity;
  
  static getInstance(): NetworkSecurity {
    if (!NetworkSecurity.instance) {
      NetworkSecurity.instance = new NetworkSecurity();
    }
    return NetworkSecurity.instance;
  }
  
  async secureRequest(url: string, options: RequestOptions): Promise<Response> {
    // 验证URL
    if (!this.isSecureUrl(url)) {
      throw new Error('不安全的URL');
    }
    
    // 添加安全头
    const secureOptions = this.addSecurityHeaders(options);
    
    // 发送请求
    const response = await this.sendRequest(url, secureOptions);
    
    // 验证响应
    this.validateResponse(response);
    
    return response;
  }
  
  private isSecureUrl(url: string): boolean {
    return url.startsWith('https://');
  }
  
  private addSecurityHeaders(options: RequestOptions): RequestOptions {
    return {
      ...options,
      headers: {
        ...options.headers,
        'Content-Security-Policy': "default-src 'self'",
        'X-Content-Type-Options': 'nosniff',
        'X-Frame-Options': 'DENY',
        'Strict-Transport-Security': 'max-age=31536000'
      }
    };
  }
}

3.2 证书验证

export class CertificateValidator {
  // 证书指纹(示例)
  private static readonly CERTIFICATE_FINGERPRINT = 
    'AA:BB:CC:DD:EE:FF:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE';
  
  async validateCertificate(certificate: string): Promise<boolean> {
    try {
      // 计算证书指纹
      const fingerprint = await this.calculateFingerprint(certificate);
      
      // 对比指纹
      return fingerprint === CertificateValidator.CERTIFICATE_FINGERPRINT;
    } catch (error) {
      console.error('证书验证失败:', error);
      return false;
    }
  }
  
  private async calculateFingerprint(certificate: string): Promise<string> {
    // 计算SHA-256指纹
    const md = cryptoFramework.createMd('SHA256');
    await md.update({ data: new Uint8Array(Buffer.from(certificate, 'utf-8').buffer) });
    const result = await md.digest();
    
    // 转换为十六进制字符串
    return Array.from(result.data)
      .map(b => b.toString(16).padStart(2, '0').toUpperCase())
      .join(':');
  }
}

四、输入验证

4.1 输入验证器

export class InputValidator {
  // 验证单词
  static validateWord(word: string): ValidationResult {
    if (!word || word.trim().length === 0) {
      return { valid: false, message: '单词不能为空' };
    }
    
    if (word.length > 100) {
      return { valid: false, message: '单词长度不能超过100' };
    }
    
    // 检查特殊字符
    const specialChars = /[<>'"&]/;
    if (specialChars.test(word)) {
      return { valid: false, message: '单词包含非法字符' };
    }
    
    return { valid: true };
  }
  
  // 验证翻译
  static validateTranslation(translation: string): ValidationResult {
    if (!translation || translation.trim().length === 0) {
      return { valid: false, message: '翻译不能为空' };
    }
    
    if (translation.length > 200) {
      return { valid: false, message: '翻译长度不能超过200' };
    }
    
    return { valid: true };
  }
  
  // 验证文件路径
  static validateFilePath(path: string): ValidationResult {
    if (!path || path.trim().length === 0) {
      return { valid: false, message: '文件路径不能为空' };
    }
    
    // 检查路径遍历攻击
    if (path.includes('..') || path.includes('~')) {
      return { valid: false, message: '非法文件路径' };
    }
    
    return { valid: true };
  }
}

interface ValidationResult {
  valid: boolean;
  message?: string;
}

4.2 SQL注入防护

export class SQLInjectionProtector {
  // 参数化查询
  static buildSafeQuery(sql: string, params: any[]): SafeQuery {
    return {
      sql,
      params
    };
  }
  
  // 转义特殊字符
  static escapeString(value: string): string {
    return value
      .replace(/\\/g, '\\\\')
      .replace(/'/g, "\\'")
      .replace(/"/g, '\\"')
      .replace(/\n/g, '\\n')
      .replace(/\r/g, '\\r')
      .replace(/\x00/g, '\\0')
      .replace(/\x1a/g, '\\Z');
  }
}

interface SafeQuery {
  sql: string;
  params: any[];
}

五、安全审计

5.1 审计日志

export class SecurityAudit {
  private static instance: SecurityAudit;
  private logs: AuditLog[] = [];
  
  static getInstance(): SecurityAudit {
    if (!SecurityAudit.instance) {
      SecurityAudit.instance = new SecurityAudit();
    }
    return SecurityAudit.instance;
  }
  
  // 记录安全事件
  logSecurityEvent(event: SecurityEvent): void {
    const log: AuditLog = {
      timestamp: Date.now(),
      event: event.type,
      user: event.user,
      action: event.action,
      resource: event.resource,
      result: event.result,
      details: event.details
    };
    
    this.logs.push(log);
    this.uploadLog(log);
  }
  
  // 检查可疑活动
  checkSuspiciousActivity(): SuspiciousActivity[] {
    const activities: SuspiciousActivity[] = [];
    
    // 检查频繁失败登录
    const failedLogins = this.logs.filter(
      log => log.event === 'login' && log.result === 'failed'
    );
    
    if (failedLogins.length > 5) {
      activities.push({
        type: 'frequent_failed_login',
        severity: 'high',
        count: failedLogins.length
      });
    }
    
    return activities;
  }
}

interface AuditLog {
  timestamp: number;
  event: string;
  user?: string;
  action: string;
  resource?: string;
  result: string;
  details?: any;
}

5.2 安全检查流程

用户操作

输入验证

验证通过?

拒绝操作

权限检查

有权限?

权限拒绝

执行操作

记录审计日志

返回结果

记录安全事件

六、安全配置

6.1 安全策略配置

export class SecurityConfig {
  // 密码策略
  static readonly PASSWORD_POLICY = {
    minLength: 8,
    requireUppercase: true,
    requireLowercase: true,
    requireNumber: true,
    requireSpecialChar: true,
    maxAge: 90 * 24 * 60 * 60 * 1000  // 90天
  };
  
  // 会话策略
  static readonly SESSION_POLICY = {
    maxInactiveTime: 30 * 60 * 1000,  // 30分钟
    maxConcurrentSessions: 3,
    secureCookie: true,
    httpOnly: true
  };
  
  // 加密策略
  static readonly ENCRYPTION_POLICY = {
    algorithm: 'AES-256',
    keySize: 256,
    ivSize: 16,
    mode: 'CBC',
    padding: 'PKCS7'
  };
}

6.2 安全检查清单

export class SecurityChecklist {
  async runSecurityCheck(): Promise<SecurityCheckResult> {
    const checks: SecurityCheck[] = [];
    
    // 检查权限配置
    checks.push(await this.checkPermissionConfig());
    
    // 检查加密配置
    checks.push(await this.checkEncryptionConfig());
    
    // 检查网络安全
    checks.push(await this.checkNetworkSecurity());
    
    // 检查输入验证
    checks.push(await this.checkInputValidation());
    
    // 检查审计日志
    checks.push(await this.checkAuditLog());
    
    return {
      passed: checks.every(c => c.passed),
      checks
    };
  }
}

图 1 数据本地存储
在这里插入图片描述

七、总结

本文详细介绍了应用安全与权限管理的实现。通过权限管理、数据加密、网络安全、输入验证和安全审计,构建了完整的安全防护体系。

核心要点

  1. 权限管理:合理申请和使用权限
  2. 数据加密:保护敏感数据安全
  3. 网络安全:使用HTTPS和证书验证
  4. 输入验证:防止注入攻击
  5. 安全审计:记录和分析安全事件

系列文章导航:
下期预告: 鸿蒙轻松背单词应用开发实战(十)-项目总结与展望

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐