通信安全:HarmonyOS开发加密通道与认证

举报
Jack20 发表于 2026/06/19 19:12:48 2026/06/19
【摘要】 通信安全:HarmonyOS开发加密通道与认证安全第一:让跨进程通信固若金汤 一、背景与动机:为什么需要通信安全? 1.1 IPC通信的安全风险跨进程通信涉及数据在不同进程间传输,存在多种安全风险:风险类型说明后果窃听数据被第三方截获敏感信息泄露篡改数据在传输中被修改业务逻辑被破坏重放旧数据包被重新发送重复操作、状态混乱冒充非法进程冒充合法服务权限绕过、数据泄露拒绝服务恶意请求耗尽资源服务...

通信安全:HarmonyOS开发加密通道与认证

安全第一:让跨进程通信固若金汤

一、背景与动机:为什么需要通信安全?

1.1 IPC通信的安全风险

跨进程通信涉及数据在不同进程间传输,存在多种安全风险:

风险类型 说明 后果
窃听 数据被第三方截获 敏感信息泄露
篡改 数据在传输中被修改 业务逻辑被破坏
重放 旧数据包被重新发送 重复操作、状态混乱
冒充 非法进程冒充合法服务 权限绕过、数据泄露
拒绝服务 恶意请求耗尽资源 服务不可用
// ❌ 不安全的通信
// 敏感数据明文传输
service.login('user', 'password123')  // 密码明文!

// 数据可被篡改
service.transfer(100, 'attacker')  // 金额可能被改

// 任何人都能调用
service.deleteAllData()  // 无权限检查

1.2 鸿蒙的安全机制

鸿蒙提供多层次的安全机制:

图片.png

1.3 安全通信流程

图片.png

二、核心原理:鸿蒙安全机制

2.1 进程隔离与沙箱

鸿蒙为每个应用创建独立的沙箱:

// 进程隔离机制
// 每个应用有独立的:
// - UID(用户ID)
// - GID(组ID)
// - 文件系统命名空间
// - 内存空间

// 示例:获取调用方身份
onRemoteRequest(code: number, data: MessageParcel, reply: MessageParcel): boolean {
    // 获取调用方的UID
    const callingUid = this.getCallingUid()
    
    // 获取调用方的PID
    const callingPid = this.getCallingPid()
    
    // 检查是否来自本应用
    const myUid = process.uid
    
    if (callingUid !== myUid) {
        // 来自其他应用,需要权限检查
        this.checkPermission(callingUid)
    }
    
    return true
}

2.2 权限控制

鸿蒙使用声明式权限系统:

// module.json5中声明权限
{
    "module": {
        "requestPermissions": [
            {
                "name": "ohos.permission.READ_CONTACTS",
                "reason": "读取通讯录",
                "usedScene": {
                    "abilities": ["MainAbility"],
                    "when": "inuse"
                }
            }
        ]
    }
}

// 服务端检查权限
import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit'

async function checkPermission(uid: number, permission: string): Promise<boolean> {
    const accessTokenId = await getAccessTokenId(uid)
    
    const atManager = abilityAccessCtrl.createAtManager()
    const result = await atManager.verifyAccessToken(accessTokenId, permission)
    
    return result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
}

2.3 AccessToken机制

AccessToken是鸿蒙的身份认证令牌:

// AccessToken结构(简化)
interface AccessToken {
    tokenID: number        // 令牌ID
    userID: number         // 用户ID
    appID: string          // 应用ID
    permissions: string[]  // 授予的权限
    expiredTime: number    // 过期时间
}

// 获取调用方的AccessTokenID
const callingTokenId = this.getCallingTokenID()

// 验证权限
const atManager = abilityAccessCtrl.createAtManager()
const grantStatus = await atManager.verifyAccessToken(callingTokenId, 'ohos.permission.SENSITIVE')

2.4 数据加密

敏感数据传输需要加密:

import { cryptoFramework } from '@kit.CryptoArchitectureKit'

// AES加密示例
async function encryptData(plainText: string, key: Uint8Array): Promise<Uint8Array> {
    // 创建对称密钥
    const symKey = await cryptoFramework.createSymKey('AES256')
    await symKey.setKeyMaterial(key)
    
    // 创建加密器
    const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7')
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null)
    
    // 加密
    const input = new Uint8Array(new TextEncoder().encode(plainText))
    const output = await cipher.doFinal(input)
    
    return output.data
}

// AES解密示例
async function decryptData(cipherText: Uint8Array, key: Uint8Array): Promise<string> {
    const symKey = await cryptoFramework.createSymKey('AES256')
    await symKey.setKeyMaterial(key)
    
    const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7')
    await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null)
    
    const output = await cipher.doFinal(cipherText)
    
    return new TextDecoder().decode(output.data)
}

三、代码实战:安全通信实现

3.1 权限检查封装

// SecurityManager.ets
import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit'
import hilog from '@ohos.hilog'

const TAG = 'SecurityManager'
const DOMAIN = 0xFF00

/**
 * 安全管理器
 * 封装权限检查、身份验证等安全功能
 */
export class SecurityManager {
    private static instance: SecurityManager
    private atManager: abilityAccessCtrl.AtManager
    
    private constructor() {
        this.atManager = abilityAccessCtrl.createAtManager()
    }
    
    static getInstance(): SecurityManager {
        if (!SecurityManager.instance) {
            SecurityManager.instance = new SecurityManager()
        }
        return SecurityManager.instance
    }
    
    /**
     * 检查调用方是否有指定权限
     * @param callingUid 调用方UID
     * @param permission 权限名
     */
    async checkPermission(callingUid: number, permission: string): Promise<boolean> {
        try {
            // 获取AccessTokenID
            const accessTokenId = await this.getAccessTokenId(callingUid)
            
            // 验证权限
            const result = await this.atManager.verifyAccessToken(accessTokenId, permission)
            
            const granted = result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
            
            hilog.info(DOMAIN, TAG, `Permission check: uid=${callingUid}, permission=${permission}, granted=${granted}`)
            
            return granted
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Check permission failed: ${err.message}`)
            return false
        }
    }
    
    /**
     * 检查多个权限
     */
    async checkPermissions(callingUid: number, permissions: string[]): Promise<boolean> {
        for (const permission of permissions) {
            const granted = await this.checkPermission(callingUid, permission)
            if (!granted) {
                return false
            }
        }
        return true
    }
    
    /**
     * 获取AccessTokenID
     */
    private async getAccessTokenId(uid: number): Promise<number> {
        // 通过UID获取应用的AccessTokenID
        const bundleName = await this.getBundleNameByUid(uid)
        
        const bundleInfo = await bundleManager.getBundleInfoForSelf(
            bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
        )
        
        return bundleInfo.appInfo.accessTokenId
    }
    
    /**
     * 通过UID获取BundleName
     */
    private async getBundleNameByUid(uid: number): Promise<string> {
        // 简化实现,实际需要查询系统
        return ''
    }
    
    /**
     * 检查是否来自本应用
     */
    isFromSelf(callingUid: number): boolean {
        return callingUid === process.uid
    }
    
    /**
     * 检查是否来自系统应用
     */
    async isSystemApp(callingUid: number): Promise<boolean> {
        try {
            const bundleName = await this.getBundleNameByUid(callingUid)
            const bundleInfo = await bundleManager.getBundleInfoForSelf(
                bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
            )
            
            return bundleInfo.appInfo.type === 'system'
        } catch (err) {
            return false
        }
    }
    
    /**
     * 获取调用方信息
     */
    async getCallerInfo(callingUid: number, callingPid: number): Promise<CallerInfo> {
        return {
            uid: callingUid,
            pid: callingPid,
            bundleName: await this.getBundleNameByUid(callingUid),
            isSystemApp: await this.isSystemApp(callingUid),
            isSelf: this.isFromSelf(callingUid)
        }
    }
}

/**
 * 调用方信息
 */
interface CallerInfo {
    uid: number
    pid: number
    bundleName: string
    isSystemApp: boolean
    isSelf: boolean
}

3.2 安全服务端实现

// SecureService.ets
import { RemoteObject, MessageParcel } from '@kit.IPCKit'
import { SecurityManager } from './SecurityManager'
import hilog from '@ohos.hilog'

const TAG = 'SecureService'
const DOMAIN = 0xFF00

/**
 * 安全服务示例
 * 演示如何在服务端实现安全控制
 */
export class SecureService extends RemoteObject {
    private securityManager: SecurityManager
    
    // 敏感操作权限要求
    private static readonly SENSITIVE_PERMISSIONS = [
        'ohos.permission.READ_SENSITIVE_DATA',
        'ohos.permission.WRITE_SENSITIVE_DATA'
    ]
    
    constructor() {
        super('com.example.ISecureService')
        this.securityManager = SecurityManager.getInstance()
    }
    
    /**
     * 处理远程请求
     */
    async onRemoteRequest(code: number, data: MessageParcel, reply: MessageParcel): Promise<boolean> {
        // 获取调用方身份
        const callingUid = this.getCallingUid()
        const callingPid = this.getCallingPid()
        
        hilog.info(DOMAIN, TAG, `Request from uid=${callingUid}, pid=${callingPid}, code=${code}`)
        
        // 检查是否来自本应用
        if (this.securityManager.isFromSelf(callingUid)) {
            // 本应用调用,跳过权限检查
            return this.handleRequest(code, data, reply)
        }
        
        // 外部应用调用,需要权限检查
        switch (code) {
            case ServiceCode.READ_DATA:
                // 读操作需要读权限
                if (!await this.securityManager.checkPermission(callingUid, 'ohos.permission.READ_SENSITIVE_DATA')) {
                    return this.handlePermissionDenied(reply)
                }
                break
                
            case ServiceCode.WRITE_DATA:
                // 写操作需要写权限
                if (!await this.securityManager.checkPermissions(callingUid, SecureService.SENSITIVE_PERMISSIONS)) {
                    return this.handlePermissionDenied(reply)
                }
                break
                
            case ServiceCode.DELETE_DATA:
                // 删除操作需要更高权限
                if (!await this.securityManager.checkPermission(callingUid, 'ohos.permission.MANAGE_SENSITIVE_DATA')) {
                    return this.handlePermissionDenied(reply)
                }
                break
                
            case ServiceCode.PUBLIC_API:
                // 公开API,无需权限
                break
                
            default:
                // 未知操作,拒绝
                return this.handleUnknownOperation(code, reply)
        }
        
        // 权限检查通过,处理请求
        return this.handleRequest(code, data, reply)
    }
    
    /**
     * 处理请求
     */
    private handleRequest(code: number, data: MessageParcel, reply: MessageParcel): boolean {
        switch (code) {
            case ServiceCode.READ_DATA:
                return this.handleReadData(data, reply)
                
            case ServiceCode.WRITE_DATA:
                return this.handleWriteData(data, reply)
                
            case ServiceCode.DELETE_DATA:
                return this.handleDeleteData(data, reply)
                
            case ServiceCode.PUBLIC_API:
                return this.handlePublicApi(data, reply)
                
            default:
                return false
        }
    }
    
    /**
     * 处理权限拒绝
     */
    private handlePermissionDenied(reply: MessageParcel): boolean {
        hilog.warn(DOMAIN, TAG, 'Permission denied')
        
        reply.writeInt(ErrorCode.PERMISSION_DENIED)
        reply.writeString('Permission denied')
        
        return true
    }
    
    /**
     * 处理未知操作
     */
    private handleUnknownOperation(code: number, reply: MessageParcel): boolean {
        hilog.warn(DOMAIN, TAG, `Unknown operation: ${code}`)
        
        reply.writeInt(ErrorCode.UNKNOWN_OPERATION)
        reply.writeString('Unknown operation')
        
        return true
    }
    
    /**
     * 处理读数据
     */
    private handleReadData(data: MessageParcel, reply: MessageParcel): boolean {
        const key = data.readString()
        
        // 读取数据(实际应从安全存储读取)
        const value = this.readSecureData(key)
        
        reply.writeInt(ErrorCode.SUCCESS)
        reply.writeString(value)
        
        return true
    }
    
    /**
     * 处理写数据
     */
    private handleWriteData(data: MessageParcel, reply: MessageParcel): boolean {
        const key = data.readString()
        const value = data.readString()
        
        // 写入数据(实际应写入安全存储)
        this.writeSecureData(key, value)
        
        reply.writeInt(ErrorCode.SUCCESS)
        
        return true
    }
    
    /**
     * 处理删除数据
     */
    private handleDeleteData(data: MessageParcel, reply: MessageParcel): boolean {
        const key = data.readString()
        
        this.deleteSecureData(key)
        
        reply.writeInt(ErrorCode.SUCCESS)
        
        return true
    }
    
    /**
     * 处理公开API
     */
    private handlePublicApi(data: MessageParcel, reply: MessageParcel): boolean {
        // 无需权限的公开操作
        reply.writeInt(ErrorCode.SUCCESS)
        reply.writeString('Public API response')
        
        return true
    }
    
    // 数据存储方法(简化)
    private secureData: Map<string, string> = new Map()
    
    private readSecureData(key: string): string {
        return this.secureData.get(key) ?? ''
    }
    
    private writeSecureData(key: string, value: string): void {
        this.secureData.set(key, value)
    }
    
    private deleteSecureData(key: string): void {
        this.secureData.delete(key)
    }
}

// 服务方法码
const enum ServiceCode {
    READ_DATA = 1,
    WRITE_DATA = 2,
    DELETE_DATA = 3,
    PUBLIC_API = 4
}

// 错误码
const enum ErrorCode {
    SUCCESS = 0,
    PERMISSION_DENIED = -1,
    UNKNOWN_OPERATION = -2
}

3.3 加密通信实现

// SecureChannel.ets
import { cryptoFramework } from '@kit.CryptoArchitectureKit'
import { MessageParcel } from '@kit.IPCKit'
import hilog from '@ohos.hilog'

const TAG = 'SecureChannel'
const DOMAIN = 0xFF00

/**
 * 安全通道
 * 提供加密通信能力
 */
export class SecureChannel {
    private aesKey: cryptoFramework.SymKey = null
    private cipher: cryptoFramework.Cipher = null
    
    /**
     * 初始化安全通道
     * 生成或设置加密密钥
     */
    async initialize(keyMaterial?: Uint8Array): Promise<void> {
        // 创建AES密钥
        this.aesKey = await cryptoFramework.createSymKey('AES256')
        
        if (keyMaterial) {
            // 使用提供的密钥
            await this.aesKey.setKeyMaterial(keyMaterial)
        } else {
            // 生成随机密钥
            const random = cryptoFramework.createRandom()
            const keyData = await random.generateRandom(32)  // 256位
            await this.aesKey.setKeyMaterial(keyData.data)
        }
        
        // 创建加密器
        this.cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7')
        
        hilog.info(DOMAIN, TAG, 'Secure channel initialized')
    }
    
    /**
     * 加密数据
     */
    async encrypt(plainText: string): Promise<EncryptedData> {
        if (!this.aesKey || !this.cipher) {
            throw new Error('Secure channel not initialized')
        }
        
        try {
            // 初始化加密模式
            await this.cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, this.aesKey, null)
            
            // 加密
            const input = new Uint8Array(new TextEncoder().encode(plainText))
            const output = await this.cipher.doFinal(input)
            
            // 生成IV(初始化向量)
            const iv = await this.generateIV()
            
            return {
                cipherText: output.data,
                iv: iv,
                algorithm: 'AES256-GCM'
            }
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Encrypt failed: ${err.message}`)
            throw err
        }
    }
    
    /**
     * 解密数据
     */
    async decrypt(encryptedData: EncryptedData): Promise<string> {
        if (!this.aesKey || !this.cipher) {
            throw new Error('Secure channel not initialized')
        }
        
        try {
            // 初始化解密模式
            await this.cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, this.aesKey, null)
            
            // 解密
            const output = await this.cipher.doFinal(encryptedData.cipherText)
            
            return new TextDecoder().decode(output.data)
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Decrypt failed: ${err.message}`)
            throw err
        }
    }
    
    /**
     * 加密MessageParcel数据
     */
    async encryptParcel(parcel: MessageParcel): Promise<MessageParcel> {
        // 读取原始数据
        const rawData = parcel.getRawData()
        
        // 加密
        const encrypted = await this.encrypt(
            new TextDecoder().decode(rawData)
        )
        
        // 写入加密数据
        const result = MessageParcel.create()
        result.writeString(JSON.stringify(encrypted))
        
        return result
    }
    
    /**
     * 解密MessageParcel数据
     */
    async decryptParcel(parcel: MessageParcel): Promise<MessageParcel> {
        // 读取加密数据
        const encryptedJson = parcel.readString()
        const encrypted: EncryptedData = JSON.parse(encryptedJson)
        
        // 解密
        const plainText = await this.decrypt(encrypted)
        
        // 写入原始数据
        const result = MessageParcel.create()
        result.writeString(plainText)
        
        return result
    }
    
    /**
     * 生成IV
     */
    private async generateIV(): Promise<Uint8Array> {
        const random = cryptoFramework.createRandom()
        const iv = await random.generateRandom(16)  // 128位IV
        return iv.data
    }
    
    /**
     * 获取密钥材料(用于密钥交换)
     */
    async getKeyMaterial(): Promise<Uint8Array> {
        if (!this.aesKey) {
            throw new Error('Key not initialized')
        }
        
        return await this.aesKey.getKeyMaterial()
    }
}

/**
 * 加密数据结构
 */
interface EncryptedData {
    cipherText: Uint8Array
    iv: Uint8Array
    algorithm: string
}

3.4 完整安全通信示例

// SecurePaymentService.ets
import { RemoteObject, MessageParcel } from '@kit.IPCKit'
import { SecurityManager } from './SecurityManager'
import { SecureChannel } from './SecureChannel'
import hilog from '@ohos.hilog'

const TAG = 'SecurePayment'
const DOMAIN = 0xFF00

/**
 * 安全支付服务
 * 演示完整的安全通信流程
 */
export class SecurePaymentService extends RemoteObject {
    private securityManager: SecurityManager
    private secureChannel: SecureChannel
    
    constructor() {
        super('com.example.ISecurePayment')
        this.securityManager = SecurityManager.getInstance()
        this.secureChannel = new SecureChannel()
    }
    
    /**
     * 初始化
     */
    async initialize(): Promise<void> {
        await this.secureChannel.initialize()
        hilog.info(DOMAIN, TAG, 'SecurePaymentService initialized')
    }
    
    /**
     * 处理远程请求
     */
    async onRemoteRequest(code: number, data: MessageParcel, reply: MessageParcel): Promise<boolean> {
        const callingUid = this.getCallingUid()
        
        // 1. 权限检查
        if (!await this.securityManager.checkPermission(callingUid, 'ohos.permission.PAYMENT')) {
            return this.errorReply(reply, 'Permission denied')
        }
        
        // 2. 解密请求数据
        let decryptedData: MessageParcel
        try {
            decryptedData = await this.secureChannel.decryptParcel(data)
        } catch (err) {
            return this.errorReply(reply, 'Decryption failed')
        }
        
        // 3. 处理请求
        let result: string
        try {
            result = await this.handlePaymentRequest(code, decryptedData)
        } catch (err) {
            return this.errorReply(reply, err.message)
        }
        
        // 4. 加密响应
        const plainReply = MessageParcel.create()
        plainReply.writeString(result)
        
        const encryptedReply = await this.secureChannel.encryptParcel(plainReply)
        
        // 5. 返回加密响应
        reply.writeByteArray(encryptedReply.getRawData())
        
        return true
    }
    
    /**
     * 处理支付请求
     */
    private async handlePaymentRequest(code: number, data: MessageParcel): Promise<string> {
        switch (code) {
            case PaymentCode.CREATE_ORDER: {
                // 读取订单信息
                const orderJson = data.readString()
                const order = JSON.parse(orderJson)
                
                // 验证订单
                this.validateOrder(order)
                
                // 创建订单
                const orderId = await this.createOrder(order)
                
                return JSON.stringify({ success: true, orderId })
            }
            
            case PaymentCode.PAY: {
                const orderId = data.readString()
                const paymentInfo = data.readString()
                
                // 执行支付
                const result = await this.executePayment(orderId, paymentInfo)
                
                return JSON.stringify(result)
            }
            
            default:
                throw new Error('Unknown operation')
        }
    }
    
    /**
     * 验证订单
     */
    private validateOrder(order: PaymentOrder): void {
        // 检查金额
        if (order.amount <= 0 || order.amount > 100000000) {
            throw new Error('Invalid amount')
        }
        
        // 检查币种
        const validCurrencies = ['CNY', 'USD', 'EUR']
        if (!validCurrencies.includes(order.currency)) {
            throw new Error('Invalid currency')
        }
        
        // 其他验证...
    }
    
    /**
     * 创建订单
     */
    private async createOrder(order: PaymentOrder): Promise<string> {
        // 实际实现:保存到数据库
        return `ORD${Date.now()}`
    }
    
    /**
     * 执行支付
     */
    private async executePayment(orderId: string, paymentInfo: string): Promise<PaymentResult> {
        // 实际实现:调用支付渠道
        return {
            success: true,
            transactionId: `TXN${Date.now()}`
        }
    }
    
    /**
     * 错误响应
     */
    private errorReply(reply: MessageParcel, message: string): boolean {
        reply.writeInt(-1)
        reply.writeString(message)
        return true
    }
}

/**
 * 支付订单
 */
interface PaymentOrder {
    amount: number
    currency: string
    subject: string
}

/**
 * 支付结果
 */
interface PaymentResult {
    success: boolean
    transactionId?: string
    error?: string
}

// 支付方法码
const enum PaymentCode {
    CREATE_ORDER = 1,
    PAY = 2
}

四、踩坑与注意事项

4.1 坑一:权限检查遗漏

问题:某些敏感操作忘记检查权限。

// ❌ 忘记检查权限
onRemoteRequest(code: number, data: MessageParcel, reply: MessageParcel): boolean {
    if (code === DELETE_ALL_DATA) {
        this.deleteAllData()  // 危险!任何人都能调用
        return true
    }
}

// ✅ 所有敏感操作都检查权限
onRemoteRequest(code: number, data: MessageParcel, reply: MessageParcel): boolean {
    const callingUid = this.getCallingUid()
    
    if (code === DELETE_ALL_DATA) {
        if (!this.checkPermission(callingUid, 'ohos.permission.MANAGE_DATA')) {
            return this.errorReply(reply, 'Permission denied')
        }
        this.deleteAllData()
        return true
    }
}

4.2 坑二:明文传输敏感数据

问题:密码、密钥等敏感数据明文传输。

// ❌ 密码明文传输
service.login('user', 'password123')

// ✅ 加密后传输
const encryptedPassword = await secureChannel.encrypt('password123')
service.login('user', encryptedPassword)

// ✅ 更好:使用哈希
import { cryptoFramework } from '@kit.CryptoArchitectureKit'

async function hashPassword(password: string, salt: Uint8Array): Promise<Uint8Array> {
    const md = cryptoFramework.createMd('SHA256')
    await md.update(new TextEncoder().encode(password))
    await md.update(salt)
    return (await md.digest()).data
}

4.3 坑三:时间检查不足

问题:请求没有时间戳,可能被重放攻击。

// ❌ 无时间检查
const data = JSON.parse(parcel.readString())
processPayment(data)  // 可能是重放的旧请求

// ✅ 检查时间戳
const data = JSON.parse(parcel.readString())
const now = Date.now()
const timestamp = data.timestamp

// 检查时间差(允许5分钟误差)
if (Math.abs(now - timestamp) > 5 * 60 * 1000) {
    throw new Error('Request expired')
}

// 检查nonce(防止重放)
if (await this.isNonceUsed(data.nonce)) {
    throw new Error('Request replay detected')
}

processPayment(data)

4.4 坑四:异常信息泄露

问题:错误信息包含敏感信息。

// ❌ 泄露敏感信息
try {
    await connectDatabase()
} catch (err) {
    reply.writeString(`Database error: ${err.message}`)
    // 可能泄露:Database error: Connection refused to 192.168.1.100:3306
}

// ✅ 通用错误信息
try {
    await connectDatabase()
} catch (err) {
    hilog.error(DOMAIN, TAG, `Database error: ${err.message}`)  // 只记录日志
    reply.writeString('Service temporarily unavailable')  // 通用错误
}

4.5 坑五:密钥管理不当

问题:密钥硬编码或存储不安全。

// ❌ 密钥硬编码
const AES_KEY = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, ...])

// ✅ 从安全存储读取
import { huks } from '@kit.DeviceAuthenticationKit'

async function getSecureKey(): Promise<Uint8Array> {
    // 使用HUKS(Hardware Universal Key Store)
    const keyAlias = 'my_aes_key'
    
    // 检查密钥是否存在
    const isExist = await huks.isKeyItemExist(keyAlias, {})
    
    if (!isExist) {
        // 生成新密钥
        const properties = [
            { 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 }
        ]
        
        await huks.generateKeyItem(keyAlias, { properties })
    }
    
    // 密钥在HUKS中,不导出到应用层
    return null  // 使用keyAlias引用
}

五、HarmonyOS 6适配指南

5.1 安全API变更

变更项 HarmonyOS 5 HarmonyOS 6
权限检查 verifyAccessToken 同上
加密API @ohos.security.cryptoFramework @kit.CryptoArchitectureKit
密钥存储 @ohos.security.huks @kit.DeviceAuthenticationKit
生物认证 @ohos.userIAM.userAuth @kit.UserAuthenticationKit

5.2 新增安全功能

// HarmonyOS 6新增:生物认证
import { userAuth } from '@kit.UserAuthenticationKit'

async function authenticateWithBiometric(): Promise<boolean> {
    const authInstance = userAuth.getUserAuthInstance({
        challenge: new Uint8Array(32),
        authType: [userAuth.UserAuthType.FINGERPRINT],
        authTrustLevel: userAuth.AuthTrustLevel.ATL3
    })
    
    const result = await authInstance.start()
    
    return result.result === userAuth.UserAuthResultCode.SUCCESS
}

// HarmonyOS 6新增:安全存储
import { huks } from '@kit.DeviceAuthenticationKit'

async function secureStore(key: string, value: Uint8Array): Promise<void> {
    // 使用HUKS加密后存储
    const encrypted = await huks.encrypt(key, value)
    
    // 存储加密数据
    // ...
}

async function secureRetrieve(key: string): Promise<Uint8Array> {
    // 读取加密数据
    // ...
    
    // 使用HUKS解密
    return await huks.decrypt(key, encryptedData)
}

5.3 安全最佳实践

// HarmonyOS 6安全通信完整示例
class SecureCommunication {
    /**
     * 安全请求流程
     */
    async secureRequest(request: Request): Promise<Response> {
        // 1. 添加时间戳和nonce
        request.timestamp = Date.now()
        request.nonce = this.generateNonce()
        
        // 2. 签名请求
        request.signature = await this.signRequest(request)
        
        // 3. 加密请求体
        const encrypted = await this.encrypt(JSON.stringify(request))
        
        // 4. 发送请求
        const response = await this.send(encrypted)
        
        // 5. 验证响应签名
        if (!await this.verifyResponse(response)) {
            throw new Error('Response verification failed')
        }
        
        // 6. 解密响应
        return await this.decrypt(response.data)
    }
    
    /**
     * 生成nonce
     */
    private generateNonce(): string {
        const random = cryptoFramework.createRandom()
        const nonce = await random.generateRandom(16)
        return Array.from(nonce.data).map(b => b.toString(16).padStart(2, '0')).join('')
    }
    
    /**
     * 签名请求
     */
    private async signRequest(request: Request): Promise<string> {
        // 使用HMAC签名
        const mac = cryptoFramework.createMac('HMAC|SHA256')
        await mac.init(this.signingKey)
        await mac.update(new TextEncoder().encode(JSON.stringify(request)))
        
        const signature = await mac.doFinal()
        return Array.from(signature.data).map(b => b.toString(16)).join('')
    }
}

六、总结

6.1 核心要点回顾

图片.png

6.2 最佳实践清单

  • [ ] 所有敏感操作检查权限
  • [ ] 敏感数据加密传输
  • [ ] 使用时间戳和nonce防重放
  • [ ] 错误信息不泄露敏感内容
  • [ ] 密钥使用HUKS安全存储
  • [ ] 实现请求签名验证
  • [ ] 定期审计安全日志
  • [ ] 遵循最小权限原则

6.3 安全检查清单

检查项 说明
权限声明 module.json5正确声明所需权限
权限检查 所有敏感操作都检查权限
数据加密 敏感数据传输前加密
密钥管理 使用HUKS管理密钥
时间验证 检查请求时间戳
重放防护 使用nonce防止重放
签名验证 验证请求和响应签名
日志安全 日志不包含敏感信息

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。