Skip to content

应用沙箱

HarmonyOS 采用应用沙箱机制,每个应用运行在独立的隔离环境中。


1. 沙箱架构

┌─────────────────────────────────────────┐
│           HarmonyOS System              │
├─────────────────────────────────────────┤
│  App Sandbox 1  │  App Sandbox 2        │
│  ┌───────────┐  │  ┌───────────┐        │
│  │ EntryAbility│ │  │ EntryAbility│    │
│  │ Data/     │  │  │ Data/     │        │
│  │ Cache/    │  │  │ Cache/    │        │
│  │ Files/    │  │  │ Files/    │        │
│  │ TokenID: A │  │  │ TokenID: B │      │
│  └───────────┘  │  └───────────┘        │
├─────────────────────────────────────────┤
│         Kernel (隔离层)                  │
└─────────────────────────────────────────┘

沙箱特点

特性说明
进程隔离每个应用独立进程
文件隔离应用数据目录独立
权限隔离基于 TokenID 的访问控制
网络隔离独立的网络命名空间

2. 沙箱目录结构

应用沙箱目录:
/data/app/el1/bundle/public/com.example.myapp/
├── entry/
│   ├── databases/      # 数据库文件
│   ├── cache/          # 缓存文件
│   ├── files/          # 普通文件
│   ├── preferences/    # 首选项配置
│   └── lib/            # 原生库
└── ...

目录访问 API

typescript
import { fileIo } from '@kit.ArkIO';

// 获取应用目录
let context = getContext() as common.UIAbilityContext;

// 缓存目录
let cacheDir = context.cacheDir;

// 文件目录
let filesDir = context.filesDir;

// 数据库目录
let databaseDir = context.databaseDir;

// 首选项目录
let preferencesDir = context.preferencesDir;

// 读取文件
let filePath = `${filesDir}/data.txt`;
let content = await fileIo.readFile(filePath);

3. 沙箱隔离机制

进程隔离

每个应用:
- 独立的 Linux 进程
- 独立的 UID/GID
- 独立的内存空间
- 独立的线程池

文件隔离

typescript
// ❌ 无法直接访问其他应用的文件
let otherAppPath = '/data/app/el1/bundle/public/com.other.app/files/data.txt';
// 访问会被内核拒绝

// ✅ 通过共享文件 URI 方式访问
let uri = 'file://shared/xxx';
let content = await fileIo.readFile(uri);

权限隔离

typescript
// 即使知道其他应用的 TokenID,也无法冒充
let myTokenId = getTokenId();
// 系统会验证 TokenID 与调用者身份匹配

4. 跨应用数据共享

方式一:FileProvider

typescript
// 提供方应用
import { dataShare } from '@kit.ArkDataShare';

// 创建共享文件 URI
let uri = dataShare.getDataShareUri('com.example.provider', 'files/data.txt');

// 接收方应用
let content = await fileIo.readFile(uri);

方式二:Want 传参

typescript
// 启动方
let want: Want = {
  bundleName: 'com.example.other',
  abilityName: 'DetailAbility',
  parameters: {
    'data': JSON.stringify({ id: 1, name: 'test' })
  }
};
context.startAbility(want);

// 接收方
let params = this.context.want.parameters;
let data = JSON.parse(params['data'] as string);

方式三:分布式数据对象

typescript
import { distributedDataObject } from '@kit.ArkDistributedDataObject';

// 创建分布式对象
let obj = distributedDataObject.create({
  namespace: 'my_namespace',
  objectID: 'shared_object'
});

// 设置值(其他设备/应用可访问)
obj.put('key', 'value');

5. URI 安全

URI 授权

typescript
import { uriAuthority } from '@kit.ArkURI';

// 授予临时 URI 权限
await uriAuthority.grantUriPermission({
  targetBundle: 'com.example.other',
  uri: 'file://shared/data.txt',
  mode: uriAuthority.GRANT_READ_ONLY
});

// 撤销权限
await uriAuthority.revokeUriPermission({
  targetBundle: 'com.example.other',
  uri: 'file://shared/data.txt'
});

URI 校验

typescript
// 校验 URI 是否合法
function isValidUri(uri: string): boolean {
  try {
    new URL(uri);
    return true;
  } catch {
    return false;
  }
}

// 防止路径遍历攻击
function sanitizePath(path: string): string {
  // 移除 ../ 等危险字符
  return path.replace(/\.\.\//g, '');
}

6. 沙箱安全最佳实践

1. 最小化文件暴露

typescript
// ✅ 推荐:只共享必要的文件
let shareableFiles = ['public_report.pdf'];

// ❌ 不推荐:共享整个目录
// grantPermission('/data/app/.../files/*');

2. 及时撤销权限

typescript
// 使用完毕后立即撤销
async function shareFile(targetBundle: string, uri: string) {
  await uriAuthority.grantUriPermission({ targetBundle, uri });
  
  try {
    // 使用文件
    await doSomething(uri);
  } finally {
    // 确保撤销
    await uriAuthority.revokeUriPermission({ targetBundle, uri });
  }
}

3. 敏感数据加密存储

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

// 加密存储
async function saveSensitiveData(data: string) {
  let encryptor = await cryptoFramework.createEncryptor('AES128');
  let encrypted = await encryptor.encrypt(data, { keyAlias: 'my_key' });
  await fileIo.writeFile(`${filesDir}/sensitive.dat`, encrypted);
}

7. 面试高频问题

Q1: 应用沙箱的作用是什么?

:沙箱隔离每个应用的运行环境,防止恶意应用访问其他应用的数据或系统资源,是鸿蒙安全模型的基础。

Q2: 如何实现跨应用数据共享?

  1. FileProvider + URI 授权
  2. Want 参数传递
  3. 分布式数据对象
  4. 公共存储服务(如相册)

Q3: 沙箱目录有哪些?

cacheDir(缓存)、filesDir(文件)、databaseDir(数据库)、preferencesDir(首选项)。


8. 与 Android 对照

概念HarmonyOSAndroid
沙箱目录/data/app/el1/bundle//data/data/package/
缓存目录cacheDirgetCacheDir()
文件目录filesDirgetFilesDir()
URI 授权grantUriPermissiongrantUriPermission
进程隔离独立进程独立进程

面试提示:沙箱机制是鸿蒙安全的基础,需理解隔离原理和跨应用共享方式。