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 权限管理要点
- 适时申请:在用户真正需要使用功能时申请权限
- 明确说明:清晰解释权限的用途和好处
- 优雅降级:权限被拒绝时提供替代方案
- 持续监控:定期检查权限状态变化
5.2 数据保护策略
- 分类分级:根据数据敏感程度采取不同保护措施
- 加密存储:敏感数据必须加密存储
- 安全传输:网络通信使用加密协议
- 及时清理:不再需要的数据及时安全删除
5.3 隐私合规要求
- 透明告知:明确告知用户数据收集和使用方式
- 用户控制:提供数据管理和删除功能
- 最小必要:只收集实现功能必需的数据
- 安全审计:定期进行安全检查和漏洞修复
需要参加鸿蒙认证的请点击 鸿蒙认证链接

浙公网安备 33010602011771号