HarmonyOS安全与隐私:权限申请与敏感数据保护实战

一、HarmonyOS安全架构概述

HarmonyOS构建了全方位的安全防护体系,从应用开发、分发到运行阶段都提供了完善的安全保障机制。安全架构主要包括应用可信、数据安全、权限管理和隐私保护四个维度。

1.1 安全分级与权限分类

HarmonyOS将权限分为普通权限敏感权限系统权限三个等级,不同等级的权限申请流程和保护要求各不相同。

权限分类对比表:

权限类型 申请方式 用户授权 使用场景 示例
普通权限 安装时自动授予 无需用户操作 不影响用户隐私的功能 网络访问、蓝牙发现
敏感权限 运行时动态申请 需要用户明确授权 涉及用户隐私数据 位置、相机、麦克风
系统权限 特殊申请流程 严格审核授权 系统级功能调用 系统设置、特殊功能

1.2 隐私保护基本原则

在HarmonyOS应用开发中,需要遵循以下隐私保护原则:

  • 最小化原则:只收集实现功能所必需的最少数据
  • 透明性原则:向用户清晰说明数据收集和使用目的
  • 目的明确原则:数据收集和使用要有明确的合法目的
  • 安全保障原则:采取技术措施保障数据安全

二、权限管理实战

2.1 权限声明配置

在应用的module.json5配置文件中声明需要使用的权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:camera_permission_reason",
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.ACCESS_FINE_LOCATION",
        "reason": "$string:location_permission_reason",
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.READ_MEDIA",
        "reason": "$string:media_permission_reason",
        "usedScene": {
          "abilities": ["MainAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

对应的权限说明字符串资源(string.json):

{
  "string": [
    {
      "name": "camera_permission_reason",
      "value": "需要访问摄像头进行拍照和视频通话"
    },
    {
      "name": "location_permission_reason", 
      "value": "需要获取位置信息提供周边服务推荐"
    },
    {
      "name": "media_permission_reason",
      "value": "需要读取相册图片用于头像设置"
    }
  ]
}

2.2 动态权限申请

实现智能的权限申请流程,根据使用场景适时请求权限:

import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';

@Component
export class PermissionManager {
  private context: common.UIAbilityContext;
  private atManager: abilityAccessCtrl.AtManager;
  
  constructor(context: common.UIAbilityContext) {
    this.context = context;
    this.atManager = abilityAccessCtrl.createAtManager();
  }
  
  // 检查权限状态
  async checkPermission(permission: string): Promise<abilityAccessCtrl.GrantStatus> {
    try {
      const grantStatus = await this.atManager.checkAccessToken(
        this.context.token,
        permission
      );
      return grantStatus;
    } catch (error) {
      console.error(`检查权限${permission}失败:`, (error as BusinessError).message);
      return abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
    }
  }
  
  // 智能权限申请
  async requestPermissions(permissions: Array<string>): Promise<abilityAccessCtrl.GrantStatus[]> {
    try {
      // 先检查已授权状态
      const results: abilityAccessCtrl.GrantStatus[] = [];
      const needRequestPermissions: Array<string> = [];
      
      for (const permission of permissions) {
        const status = await this.checkPermission(permission);
        results.push(status);
        
        if (status !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
          needRequestPermissions.push(permission);
        }
      }
      
      // 如果有需要申请的权限
      if (needRequestPermissions.length > 0) {
        const requestResult = await this.atManager.requestPermissionsFromUser(
          this.context,
          needRequestPermissions
        );
        
        // 更新最终结果
        for (let i = 0; i < permissions.length; i++) {
          const permission = permissions[i];
          const index = needRequestPermissions.indexOf(permission);
          if (index !== -1) {
            results[i] = requestResult.authResults[index].grantStatus;
          }
        }
      }
      
      return results;
    } catch (error) {
      console.error('权限申请失败:', (error as BusinessError).message);
      throw error;
    }
  }
  
  // 场景化权限申请 - 相机权限
  async requestCameraPermissionForPhoto(): Promise<boolean> {
    const permissions = ['ohos.permission.CAMERA'];
    const results = await this.requestPermissions(permissions);
    
    if (results[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      return true;
    } else {
      // 权限被拒绝,显示引导界面
      this.showPermissionGuide('camera');
      return false;
    }
  }
  
  // 显示权限引导界面
  private showPermissionGuide(permissionType: string): void {
    // 实现权限引导逻辑,解释为什么需要这个权限
    console.info(`显示${permissionType}权限引导界面`);
  }
}

2.3 权限使用最佳实践

@Entry
@Component
struct CameraComponent {
  @State hasCameraPermission: boolean = false;
  private permissionManager: PermissionManager | null = null;
  
  aboutToAppear(): void {
    this.permissionManager = new PermissionManager(getContext(this) as common.UIAbilityContext);
    this.checkPermissions();
  }
  
  async checkPermissions(): Promise<void> {
    if (!this.permissionManager) return;
    
    const status = await this.permissionManager.checkPermission('ohos.permission.CAMERA');
    this.hasCameraPermission = status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  }
  
  async openCamera(): Promise<void> {
    if (!this.permissionManager) return;
    
    if (!this.hasCameraPermission) {
      const granted = await this.permissionManager.requestCameraPermissionForPhoto();
      if (!granted) {
        // 用户拒绝授权,显示友好提示
        this.showPermissionDeniedDialog();
        return;
      }
      this.hasCameraPermission = true;
    }
    
    // 执行相机相关操作
    this.startCamera();
  }
  
  build() {
    Column({ space: 20 }) {
      Button('拍照')
        .enabled(this.hasCameraPermission)
        .onClick(() => this.openCamera())
        .backgroundColor(this.hasCameraPermission ? '#007DFF' : '#CCCCCC')
      
      if (!this.hasCameraPermission) {
        Text('需要相机权限才能使用拍照功能')
          .fontSize(14)
          .fontColor('#FF6B6B')
      }
    }
    .padding(20)
    .width('100%')
  }
}

三、敏感数据保护实战

3.1 数据加密存储

使用HarmonyOS提供的安全加密API保护敏感数据:

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

@Component
export class SecureDataManager {
  private keyAlias: string = 'user_sensitive_data_key';
  
  // 生成加密密钥
  async generateEncryptionKey(): Promise<void> {
    const properties: Array<huks.HuksParam> = [
      {
        tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
        value: huks.HuksKeyAlg.HUKS_ALG_AES
      },
      {
        tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
        value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256
      },
      {
        tag: huks.HuksTag.HUKS_TAG_PURPOSE,
        value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | 
                huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
      },
      {
        tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
        value: huks.HuksCipherMode.HUKS_MODE_GCM
      },
      {
        tag: huks.HuksTag.HUKS_TAG_PADDING,
        value: huks.HuksKeyPadding.HUKS_PADDING_NONE
      },
      {
        tag: huks.HuksTag.HUKS_TAG_DIGEST,
        value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256
      }
    ];
    
    const options: huks.HuksOptions = {
      properties: properties
    };
    
    try {
      await huks.generateKeyItem(this.keyAlias, options);
      console.info('加密密钥生成成功');
    } catch (error) {
      console.error('加密密钥生成失败:', error);
      throw error;
    }
  }
  
  // 加密数据
  async encryptData(plainText: string): Promise<ArrayBuffer> {
    try {
      const cipher = cryptoFramework.createCipher(cryptoFramework.CryptoMode.AES_256 | 
                                                 cryptoFramework.CryptoMode.GCM);
      
      // 获取密钥
      const key = await this.getKey();
      await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, null);
      
      // 加密数据
      const input: cryptoFramework.DataBlob = { data: new TextEncoder().encode(plainText) };
      const output = await cipher.doFinal(input);
      
      return output.data;
    } catch (error) {
      console.error('数据加密失败:', error);
      throw error;
    }
  }
  
  // 解密数据
  async decryptData(cipherData: ArrayBuffer): Promise<string> {
    try {
      const cipher = cryptoFramework.createCipher(cryptoFramework.CryptoMode.AES_256 | 
                                                 cryptoFramework.CryptoMode.GCM);
      
      // 获取密钥
      const key = await this.getKey();
      await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, key, null);
      
      // 解密数据
      const input: cryptoFramework.DataBlob = { data: new Uint8Array(cipherData) };
      const output = await cipher.doFinal(input);
      
      return new TextDecoder().decode(output.data);
    } catch (error) {
      console.error('数据解密失败:', error);
      throw error;
    }
  }
}

3.2 安全数据存储实现

结合加密功能实现安全的数据存储管理器:

import preferences from '@ohos.data.preferences';

@Component
export class SecurePreferencesManager {
  private preferences: preferences.Preferences | null = null;
  private secureDataManager: SecureDataManager;
  private context: common.UIAbilityContext;
  
  constructor(context: common.UIAbilityContext) {
    this.context = context;
    this.secureDataManager = new SecureDataManager();
    this.initPreferences();
  }
  
  async initPreferences(): Promise<void> {
    try {
      this.preferences = await preferences.getPreferences(this.context, 'secure_user_data');
    } catch (error) {
      console.error('Preferences初始化失败:', error);
    }
  }
  
  // 安全存储字符串数据
  async putSecureString(key: string, value: string): Promise<void> {
    if (!this.preferences) {
      throw new Error('Preferences未初始化');
    }
    
    try {
      // 加密数据
      const encryptedData = await this.secureDataManager.encryptData(value);
      
      // 转换为Base64存储
      const base64Data = this.arrayBufferToBase64(encryptedData);
      await this.preferences.put(key, base64Data);
      await this.preferences.flush();
      
      console.info(`安全存储数据成功,键: ${key}`);
    } catch (error) {
      console.error('安全存储数据失败:', error);
      throw error;
    }
  }
  
  // 安全读取字符串数据
  async getSecureString(key: string, defaultValue: string = ''): Promise<string> {
    if (!this.preferences) {
      return defaultValue;
    }
    
    try {
      const base64Data = await this.preferences.get(key, '');
      if (base64Data === '') {
        return defaultValue;
      }
      
      // 解码Base64
      const encryptedData = this.base64ToArrayBuffer(base64Data);
      
      // 解密数据
      return await this.secureDataManager.decryptData(encryptedData);
    } catch (error) {
      console.error('安全读取数据失败:', error);
      return defaultValue;
    }
  }
  
  // 存储敏感用户信息
  async saveUserCredentials(userId: string, token: string, userInfo: any): Promise<void> {
    try {
      await this.putSecureString('user_id', userId);
      await this.putSecureString('access_token', token);
      await this.putSecureString('user_info', JSON.stringify(userInfo));
      
      console.info('用户凭证保存成功');
    } catch (error) {
      console.error('用户凭证保存失败:', error);
      throw error;
    }
  }
  
  // 清理敏感数据
  async clearSensitiveData(): Promise<void> {
    if (!this.preferences) return;
    
    try {
      await this.preferences.delete('user_id');
      await this.preferences.delete('access_token');
      await this.preferences.delete('user_info');
      await this.preferences.flush();
      
      console.info('敏感数据清理完成');
    } catch (error) {
      console.error('敏感数据清理失败:', error);
    }
  }
  
  private arrayBufferToBase64(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    let binary = '';
    for (let i = 0; i < bytes.byteLength; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary);
  }
  
  private base64ToArrayBuffer(base64: string): ArrayBuffer {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    return bytes.buffer;
  }
}

3.3 网络安全传输

实现安全的网络通信,保护数据传输过程中的隐私:

import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';

@Component
export class SecureHttpClient {
  private httpRequest: http.HttpRequest | null = null;
  
  constructor() {
    this.initHttpClient();
  }
  
  private initHttpClient(): void {
    this.httpRequest = http.createHttp();
  }
  
  // 安全的POST请求
  async securePost(url: string, data: any, headers?: Object): Promise<any> {
    if (!this.httpRequest) {
      throw new Error('HTTP客户端未初始化');
    }
    
    try {
      // 添加安全头部
      const securityHeaders = {
        'Content-Type': 'application/json',
        'X-Request-ID': this.generateRequestId(),
        'Timestamp': Date.now().toString(),
        ...headers
      };
      
      // 请求体加密(可选,根据服务端要求)
      const encryptedData = await this.encryptRequestData(data);
      
      const options: http.HttpRequestOptions = {
        method: http.RequestMethod.POST,
        header: securityHeaders,
        extraData: encryptedData,
        connectTimeout: 30000,
        readTimeout: 30000
      };
      
      const response = await this.httpRequest.request(url, options);
      
      if (response.responseCode === http.ResponseCode.OK) {
        // 解密响应数据(如果需要)
        return await this.decryptResponseData(response.result);
      } else {
        throw new Error(`HTTP错误: ${response.responseCode}`);
      }
    } catch (error) {
      console.error('安全POST请求失败:', error);
      throw error;
    }
  }
  
  // 生成请求ID
  private generateRequestId(): string {
    return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  // 加密请求数据
  private async encryptRequestData(data: any): Promise<string> {
    // 简单的Base64编码,实际项目中应使用更安全的加密方案
    return btoa(JSON.stringify(data));
  }
  
  // 解密响应数据
  private async decryptResponseData(encryptedData: string): Promise<any> {
    try {
      const decodedData = atob(encryptedData);
      return JSON.parse(decodedData);
    } catch (error) {
      console.error('响应数据解密失败:', error);
      return encryptedData;
    }
  }
  
  // 清理资源
  destroy(): void {
    if (this.httpRequest) {
      this.httpRequest.destroy();
      this.httpRequest = null;
    }
  }
}

四、隐私合规实践

4.1 隐私政策集成

确保应用符合隐私保护法规要求:

@Component
export class PrivacyManager {
  private context: common.UIAbilityContext;
  private privacyAccepted: boolean = false;
  
  constructor(context: common.UIAbilityContext) {
    this.context = context;
    this.checkPrivacyStatus();
  }
  
  async checkPrivacyStatus(): Promise<void> {
    const prefs = await preferences.getPreferences(this.context, 'privacy_settings');
    this.privacyAccepted = await prefs.get('privacy_accepted', false);
  }
  
  // 显示隐私政策
  async showPrivacyPolicy(): Promise<boolean> {
    return new Promise((resolve) => {
      // 实际项目中应该显示完整的隐私政策界面
      AlertDialog.show({
        title: '隐私政策',
        message: '我们高度重视您的隐私保护,请阅读并同意我们的隐私政策',
        primaryButton: {
          value: '同意',
          action: async () => {
            await this.acceptPrivacyPolicy();
            resolve(true);
          }
        },
        secondaryButton: {
          value: '拒绝',
          action: () => {
            resolve(false);
          }
        }
      });
    });
  }
  
  async acceptPrivacyPolicy(): Promise<void> {
    const prefs = await preferences.getPreferences(this.context, 'privacy_settings');
    await prefs.put('privacy_accepted', true);
    await prefs.flush();
    this.privacyAccepted = true;
  }
  
  // 检查数据收集同意状态
  async canCollectData(): Promise<boolean> {
    if (!this.privacyAccepted) {
      return false;
    }
    
    const prefs = await preferences.getPreferences(this.context, 'privacy_settings');
    return await prefs.get('data_collection_accepted', false);
  }
  
  // 用户数据清理请求
  async processDataDeletionRequest(userId: string): Promise<void> {
    try {
      // 清理本地数据
      await this.deleteUserData(userId);
      
      // 通知服务器删除数据
      await this.notifyServerDataDeletion(userId);
      
      console.info(`用户${userId}数据删除完成`);
    } catch (error) {
      console.error('数据删除处理失败:', error);
      throw error;
    }
  }
}

4.2 完整的应用安全集成示例

@Entry
@Component
struct SecureApp {
  @State isPrivacyAccepted: boolean = false;
  @State isLoading: boolean = true;
  
  private privacyManager: PrivacyManager | null = null;
  private permissionManager: PermissionManager | null = null;
  
  aboutToAppear(): void {
    this.initSecurityManagers();
  }
  
  async initSecurityManagers(): Promise<void> {
    const context = getContext(this) as common.UIAbilityContext;
    
    this.privacyManager = new PrivacyManager(context);
    this.permissionManager = new PermissionManager(context);
    
    this.isPrivacyAccepted = await this.privacyManager.checkPrivacyStatus();
    this.isLoading = false;
    
    if (!this.isPrivacyAccepted) {
      const accepted = await this.privacyManager.showPrivacyPolicy();
      this.isPrivacyAccepted = accepted;
      
      if (!accepted) {
        // 用户拒绝隐私政策,退出应用
        this.exitApp();
      }
    }
  }
  
  build() {
    if (this.isLoading) {
      // 加载界面
      Column() {
        LoadingProgress()
        Text('安全检查中...')
          .fontSize(16)
          .margin({ top: 20 })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    } else if (!this.isPrivacyAccepted) {
      // 隐私政策界面
      PrivacyPolicyPage({
        onAccept: () => {
          this.isPrivacyAccepted = true;
        },
        onReject: () => {
          this.exitApp();
        }
      })
    } else {
      // 主应用界面
      MainAppPage({
        permissionManager: this.permissionManager
      })
    }
  }
  
  private exitApp(): void {
    // 安全退出应用
    getContext(this).terminateSelf().then(() => {
      console.info('应用安全退出');
    });
  }
}

五、安全最佳实践总结

5.1 权限管理要点

  1. 适时申请:在用户真正需要使用功能时申请权限
  2. 明确说明:清晰解释权限的用途和好处
  3. 优雅降级:权限被拒绝时提供替代方案
  4. 持续监控:定期检查权限状态变化

5.2 数据保护策略

  1. 分类分级:根据数据敏感程度采取不同保护措施
  2. 加密存储:敏感数据必须加密存储
  3. 安全传输:网络通信使用加密协议
  4. 及时清理:不再需要的数据及时安全删除

5.3 隐私合规要求

  1. 透明告知:明确告知用户数据收集和使用方式
  2. 用户控制:提供数据管理和删除功能
  3. 最小必要:只收集实现功能必需的数据
  4. 安全审计:定期进行安全检查和漏洞修复

需要参加鸿蒙认证的请点击 鸿蒙认证链接

posted @ 2025-10-30 15:41  猫林老师  阅读(13)  评论(0)    收藏  举报