HarmonyOS / ArkTS Security
This file extends common/security.md with HarmonyOS-specific security practices.
This file extends common/security.md with HarmonyOS-specific security practices.
--- paths:
---
This file extends [common/security.md](../common/security.md) with HarmonyOS-specific security practices.
All system API calls requiring permissions must be declared:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_permission_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}Before calling system APIs, verify:
import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
async function checkAndRequestPermission(permission: Permissions): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
const bundleInfo = await bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
);
const tokenId = bundleInfo.appInfo.accessTokenId;
const grantStatus = await atManager.checkAccessToken(tokenId, permission);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
return true;
}
const result = await atManager.requestPermissionsFromUser(getContext(), [permission]);
return result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}// BAD: hardcoded secret
const API_KEY: string = 'sk-xxxxxxxxxxxx';
// GOOD: from build profile config (non-sensitive)
import { BuildProfile } from 'BuildProfile';
const endpoint = BuildProfile.API_ENDPOINT;
// GOOD: use HUKS to encrypt/decrypt data without exposing key material
import { huks } from '@kit.UniversalKeystoreKit';
async function decryptWithKeystore(alias: string, nonce: Uint8Array, aad: Uint8Array, cipherData: Uint8Array): Promise<Uint8Array> {
const options: huks.HuksOptions = {
properties: [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: 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_NONCE, value: nonce },
{ tag: huks.HuksTag.HUKS_TAG_ASSOCIATED_DATA, value: aad }
],
inData: cipherData
};
const handle = await huks.initSession(alias, options);
const result = await huks.finishSession(handle.handle, options);
return result.outData;
}// Validate before navigation
function handleDeepLink(uri: string): void {
const allowedPaths: string[] = ['detail', 'settings', 'profile'];
const parsed = new URL(uri);
const path = parsed.pathname.replace('/', '');
if (!allowedPaths.includes(path)) {
hilog.warn(0x0000, 'DeepLink', 'Invalid deep link path: %{public}s', path);
return;
}
navPathStack.pushPath({ name: path });
}