Administrator
发布于 2026-09-01 / 47 阅读
0
0

鸿蒙开发系列(第12篇):安全机制与权限管理——应用签名、ACL与隐私合规

鸿蒙开发系列 · 中级篇

前言

上一篇我们写了一个天气速查元服务,功能跑通了,但有个问题没解决:如果它需要获取用户定位,该怎么申请位置权限?如果它需要读取通讯录来实现"分享给好友",系统会允许吗?如果它想访问相册选取图片,用户会看到怎样的授权弹窗?

在HarmonyOS NEXT(API 12+)中,安全架构经历了根本性的重构。Android那套"安装时一次性授权"的模型被彻底抛弃,取而代之的是更细粒度、更动态、更透明的权限管理体系。对于元服务而言,安全约束更加严格——部分高危权限直接对元服务关闭。

安全不是写完功能再"打补丁",而是贯穿整个开发周期的底线思维。本文将从应用签名、权限模型、ACL访问控制、隐私合规四个层面,帮你建立鸿蒙安全开发的完整认知。


一、HarmonyOS安全架构概览

1.1 四层安全体系

HarmonyOS的安全设计从芯片到应用分为四个层次:

┌─────────────────────────────────────────┐
│  第4层:应用层安全                        │
│  签名验证、权限管控、隐私合规、数据加密      │
├─────────────────────────────────────────┤
│  第3层:框架层安全                        │
│  沙箱隔离、IPC鉴权、Ability访问控制        │
├─────────────────────────────────────────┤
│  第2层:系统层安全                        │
│  内核安全、文件系统加密、可信执行环境TEE     │
├─────────────────────────────────────────┤
│  第1层:硬件层安全                        │
│  安全芯片、可信启动、硬件加密引擎            │
└─────────────────────────────────────────┘

作为应用开发者,我们主要在第4层工作,但必须理解:鸿蒙的权限管控不是"框架层的一个模块",而是从硬件信任根一路延伸上来的完整链条。这也是为什么鸿蒙能做到不允许用户手动关闭权限管控——底层安全架构不给你绕过它的机会。

1.2 应用沙箱与隔离机制

每个HarmonyOS应用都运行在独立的沙箱中:

  • 文件系统隔离:应用只能访问自己的 /data/app/el1/<bundleName> 目录,无法直接读写其他应用的文件

  • 进程隔离:每个应用运行在独立的进程中,通过IPC(进程间通信)进行数据交换

  • 网络隔离:应用默认只能访问公网,局域网通信需要额外申请权限

  • 内存隔离:应用无法访问其他进程的内存空间

沙箱机制对开发者最直接的影响是:没有全局存储。Android那种"写个文件到SD卡大家都能读"的做法在HarmonyOS中行不通。数据共享必须通过系统提供的标准化接口(如Data Ability、分布式数据服务)。


二、应用签名机制

2.1 签名体系的三层结构

HarmonyOS采用三层签名体系,比Android的单一签名更严格:

层级

签名名称

签发方

作用

第一层

HAP签名

开发者

证明HAP包未被篡改

第二层

应用签名

华为应用市场

证明应用经过市场审核

第三层

系统签名

华为

预置系统应用专用

开发者只需要关注第一层。当你用DevEco Studio构建HAP时,会自动使用你配置的数字证书进行签名。

2.2 数字证书配置实战

在DevEco Studio中配置签名:

方式一:自动签名(调试阶段推荐)

# File → Project Structure → Signing Configs → 勾选"Automatically generate signature"

DevEco Studio会自动生成调试证书,适合开发和联调阶段。

方式二:手动签名(发布必备)

正式上架必须使用手动签名,步骤如下:

  1. 生成密钥对:

    keytool -genkeypair -alias "myapp" -keyalg EC -keysize 256 \
      -sigalg SHA256withECDSA -dname "CN=MyCompany, O=MyOrg, C=CN" \
      -keystore myapp.p12 -storetype pkcs12 -validity 3650
    
  2. 生成证书请求文件(CSR):

    keytool -certreq -alias "myapp" -keystore myapp.p12 -file myapp.csr
    
  3. 在AppGallery Connect申请发布证书:

    • 登录 AppGallery Connect

    • 进入"证书、APP ID和Profile"

    • 上传CSR,下载 .cer 证书文件

  4. 配置Profile文件:
    Profile(.p7b)是HarmonyOS特有的配置文件,包含:

    • 应用包名

    • 允许申请的权限列表

    • 证书绑定关系

    • 调试/发布类型

  5. 在DevEco Studio中配置:

    // build-profile.json5
    {
      "app": {
        "signingConfigs": [
          {
            "name": "release",
            "type": "HarmonyOS",
            "material": {
              "certpath": "/path/to/release.cer",
              "storePassword": "******",
              "keyAlias": "myapp",
              "keyPassword": "******",
              "profile": "/path/to/release.p7b",
              "signAlg": "SHA256withECDSA",
              "storeFile": "/path/to/myapp.p12"
            }
          }
        ]
      }
    }
    

2.3 签名校验的常见问题

问题

原因

解决

安装时报"签名不一致"

同一设备上已安装不同签名的同名包

卸载旧包或更换包名

Profile过期

调试Profile有效期通常为1年

重新申请Profile

权限申请被拒

Profile中未包含该权限

在AGC后台的Profile配置中添加权限

元服务签名失败

元服务必须使用发布证书

检查证书类型是否为release


三、权限管理模型

3.1 权限分级体系

HarmonyOS NEXT将权限分为三个等级:

等级

名称

授权方式

示例

normal

普通权限

安装时自动授予

网络访问、Wi-Fi状态、振动

user_grant

用户授权权限

运行时弹窗申请

定位、相机、麦克风、相册

system_grant

系统授权权限

需特殊申请,一般应用不可用

读取短信、安装应用、系统设置

对于元服务(Atomic Service),约束更严格:

  • normal权限:可正常使用

  • user_grant权限:可申请,但用户每次使用都可能被要求授权

  • system_grant权限:元服务原则上不可申请(个别白名单除外)

3.2 运行时权限申请实战

以定位权限为例,展示完整的申请流程:

// entry/src/main/ets/utils/PermissionManager.ets
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';

export class PermissionManager {
  // 检查权限是否已授予
  static checkPermission(permission: Permissions): boolean {
    const atManager = abilityAccessCtrl.createAtManager();
    const authStatus = atManager.checkAccessTokenSync(permission);
    return authStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  }

  // 申请单个权限
  static async requestPermission(permission: Permissions, reason: string): Promise<boolean> {
    const atManager = abilityAccessCtrl.createAtManager();

    // 先检查
    if (this.checkPermission(permission)) {
      return true;
    }

    // 申请授权
    const authResults = await atManager.requestPermissionsFromUser(
      getContext(),
      [permission]
    );

    const granted = authResults.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;

    if (!granted) {
      promptAction.showToast({
        message: `需要${reason}权限才能继续使用`
      });
    }

    return granted;
  }

  // 批量申请权限
  static async requestPermissions(
    permissions: Array<{ perm: Permissions; reason: string }>
  ): Promise<boolean> {
    const needRequest = permissions.filter(p => !this.checkPermission(p.perm));

    if (needRequest.length === 0) {
      return true;
    }

    const atManager = abilityAccessCtrl.createAtManager();
    const authResults = await atManager.requestPermissionsFromUser(
      getContext(),
      needRequest.map(p => p.perm)
    );

    const allGranted = authResults.authResults.every(
      r => r === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    );

    if (!allGranted) {
      const denied = authResults.permissions.filter((_, i) =>
        authResults.authResults[i] !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
      );
      promptAction.showToast({
        message: `以下权限被拒绝:${denied.join(', ')}`
      });
    }

    return allGranted;
  }
}

在页面中使用:

// entry/src/main/ets/pages/LocationPage.ets
import { PermissionManager } from '../utils/PermissionManager';
import { geoLocationManager } from '@kit.LocationKit';

@Entry
@Component
struct LocationPage {
  @State locationText: string = '点击获取位置';

  async getLocation() {
    const granted = await PermissionManager.requestPermission(
      'ohos.permission.LOCATION',
      '定位'
    );

    if (!granted) return;

    try {
      const location = await geoLocationManager.getCurrentLocation();
      this.locationText = `纬度:${location.latitude.toFixed(4)},经度:${location.longitude.toFixed(4)}`;
    } catch (err) {
      this.locationText = '获取位置失败';
    }
  }

  build() {
    Column({ space: 20 }) {
      Text(this.locationText)
        .fontSize(16)
        .fontColor('#333')

      Button('获取当前位置')
        .onClick(() => this.getLocation())
    }
    .width('100%')
    .height('100%')
    .padding(24)
  }
}

3.3 权限配置:module.json5

所有申请的权限必须在 module.json5 中声明:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:perm_internet_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:perm_location_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:perm_camera_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

when 字段有两个值:

  • always:后台也能使用该权限(如网络)

  • inuse:只有应用在前台时才能使用(如定位、相机)


四、ACL访问控制与组件可见性

4.1 Ability的exported属性

在HarmonyOS中,每个Ability默认是私有的,其他应用无法直接启动它。如果需要暴露给外部,必须显式设置 exported: true:

{
  "abilities": [
    {
      "name": "EntryAbility",
      "exported": true,
      "skills": [
        {
          "actions": ["action.system.home"],
          "entities": ["entity.system.home"]
        }
      ]
    },
    {
      "name": "InternalAbility",
      "exported": false
    }
  ]
}

安全建议:最小暴露原则。只有真正需要被外部调用的Ability才设置exported,且务必配置skills过滤条件,防止被恶意应用随意唤起。

4.2 应用间数据共享的三种方式

由于沙箱隔离,应用间不能直接共享文件。HarmonyOS提供了三种标准化共享方式:

方式

适用场景

安全级别

Data Ability

结构化数据共享(如通讯录、日程)

高,需授权

文件URI分享

临时分享单个文件

中,接收方有临时读取权

分布式数据

跨设备数据同步

高,需同一华为账号

文件URI分享实战:

import { uniformTypeDescriptor, fileUri } from '@kit.CoreFileKit';
import { wantConstant } from '@kit.AbilityKit';

async function shareImage(imagePath: string) {
  const uri = fileUri.getUriFromPath(imagePath);

  const want = {
    action: wantConstant.Action.ACTION_SEND,
    type: 'image/png',
    parameters: {
      [wantConstant.Params.PARAM_STREAM]: uri
    }
  };

  const context = getContext();
  await context.startAbility(want);
}

4.3 元服务的特殊安全约束

元服务由于免安装的特性,安全模型更加严格:

元服务权限黑名单(不可申请):
├── ohos.permission.READ_CONTACTS      // 读取通讯录
├── ohos.permission.WRITE_CONTACTS     // 写入通讯录
├── ohos.permission.READ_CALL_LOG      // 读取通话记录
├── ohos.permission.WRITE_CALL_LOG     // 写入通话记录
├── ohos.permission.READ_SMS           // 读取短信
├── ohos.permission.SEND_SMS           // 发送短信
├── ohos.permission.INSTALL_BUNDLE     // 安装应用
├── ohos.permission.UNINSTALL_BUNDLE   // 卸载应用
└── ohos.permission.SET_TIME           // 设置系统时间

如果你的元服务确实需要通讯录相关能力,正确做法是:

  1. 调用系统提供的系统Picker(如联系人选择器)

  2. 由用户在系统UI中主动选择,而非直接读取

// 调用系统联系人选择器,而非直接申请READ_CONTACTS
import { contactPicker } from '@kit.ContactKit';

async function pickContact() {
  const contact = await contactPicker.selectContact();
  if (contact) {
    console.info(`选中联系人:${contact.name}, ${contact.phoneNumber}`);
  }
}

五、隐私合规与数据保护

5.1 隐私清单(Privacy Manifest)

HarmonyOS NEXT引入了隐私清单机制,要求开发者在 module.json5 中声明数据收集行为:

{
  "module": {
    "metadata": [
      {
        "name": "privacy_manifest",
        "value": {
          "dataCollected": [
            {
              "type": "location",
              "purpose": "提供基于位置的天气服务",
              "optional": false,
              "shared": false
            },
            {
              "type": "userContent",
              "purpose": "用户主动上传的图片",
              "optional": true,
              "shared": false
            }
          ],
          "thirdPartySDKs": [
            {
              "name": "某某统计SDK",
              "purpose": "应用数据分析"
            }
          ]
        }
      }
    ]
  }
}

这些信息会在应用市场的详情页展示,用户下载前就能清楚知道你的应用会收集哪些数据。

5.2 数据加密最佳实践

数据类型

加密方式

HarmonyOS API

本地敏感配置

AES-256-GCM

@kit.CryptoKit

用户登录凭证

硬件级加密

KeyStore + TEE

网络传输数据

TLS 1.3

系统网络栈默认支持

数据库内容

SQLCipher

RDB加密配置

RDB数据库加密示例:

import { relationalStore } from '@kit.ArkData';

const config: relationalStore.StoreConfig = {
  name: 'secure_db.db',
  securityLevel: relationalStore.SecurityLevel.S3, // 加密存储
  encrypt: true,
  // 密钥由系统自动管理,无需手动传入
};

const store = await relationalStore.getRdbStore(getContext(), config);

六、小结与下篇预告

安全是HarmonyOS的基石,也是开发者最容易忽视的领域。本文从四个维度建立了完整认知:

  1. 签名机制:三层签名体系、数字证书配置、Profile文件管理

  2. 权限模型:normal/user_grant/system_grant三级划分、运行时动态申请

  3. 访问控制:exported最小暴露、应用间数据共享的标准化方式、元服务特殊约束

  4. 隐私合规:隐私清单声明、数据加密实践

安全机制保障的是"底线",而用户体验的上限则由系统能力的灵活调度决定。元服务和普通应用都需要在后台执行一些任务——定时刷新天气、接收推送消息、后台下载文件。第13篇将深入鸿蒙的推送服务与后台任务管理,讲解Push Kit、Work Scheduler、后台限制策略,以及如何在严格的系统约束下实现流畅的用户体验。


参考阅读


评论