HarmonyOS ArkWeb 安全治理实战:白名单、JSBridge、Cookie 与文件边界

ArkWeb 能让 HarmonyOS 应用快速承载活动页、帮助中心、协议页和混合业务,但它也会把 Web 风险带进原生应用:加载了非可信域名,JSBridge 暴露过多能力,Cookie 没有隔离,文件上传下载没有边界,都会影响用户数据和审核解释。ArkWeb 安全治理的目标不是拒绝混合页面,而是让每一次加载、桥接、存储和文件操作都经过可控规则。

请添加图片描述

本文会拆四条主线:

  1. URL 加载前先做白名单和场景判断。
  2. JSBridge 按接口分级,不给 H5 任意调用原生能力。
  3. Cookie、缓存和登录态要有清理策略。
  4. 文件上传下载要限制类型、大小和来源。

1. ArkWeb 容器先定边界

一个安全的 Web 容器至少要明确三件事:哪些地址能加载,哪些桥接接口能调用,哪些数据能留在容器里。不要把活动页、协议页、支付页、客服页全放进同一个“万能 WebView”。

请添加图片描述

边界 处理内容 常见风险
URL 协议、域名、路径、跳转链 非可信站点打开
Bridge 接口名称、参数、调用场景 H5 越权调用原生能力
Cookie 主站登录态、第三方 Cookie、退出清理 账号残留或串号
文件 上传类型、大小、下载目录 非法文件进入应用

先把边界画清楚,再写容器代码。否则后面发现风险时,只能在页面里不断补 if

2. ArkWeb 资料边界和工程目录

ArkWeb 文档提供 Web 组件、页面加载、生命周期、JavaScript 交互、权限与隐私等能力说明。工程上要把组件使用和安全策略分开。

资料入口 工程落点
ArkWeb 概述 明确 Web 组件能力范围
使用 Web 组件加载页面 URL 加载、页面生命周期和错误处理
Web 与应用侧交互 JSBridge 能力边界和参数约束
ArkWeb 安全与隐私 安全加载、隐私保护和权限控制

建议目录:

entry/src/main/ets/
  common/web/UrlPolicy.ets
  common/web/BridgeGuard.ets
  common/web/CookieScope.ets
  common/web/FileBoundary.ets
  common/web/WebAuditLog.ets
  pages/web/SafeWebPage.ets

SafeWebPage 负责渲染,策略模块负责判断。不要让页面直接决定能否调用某个桥接接口。

3. UrlPolicy 控制可加载地址

Web 容器加载前必须先判断协议、域名和路径。只校验域名还不够,某些路径可能是开放跳转或不适合在 App 内打开。

export interface UrlDecision {
  allowed: boolean
  reason?: string
  normalizedUrl?: string
}

export class UrlPolicy {
  private readonly hosts = ['secure.example.com', 'help.example.com']
  private readonly pathPrefixes = ['/activity/', '/help/', '/agreement/']

  decide(rawUrl: string): UrlDecision {
    try {
      const url = new URL(rawUrl)
      if (url.protocol !== 'https:') {
        return { allowed: false, reason: '仅允许 HTTPS 页面' }
      }
      if (!this.hosts.includes(url.hostname)) {
        return { allowed: false, reason: '域名不在 Web 容器白名单内' }
      }
      if (!this.pathPrefixes.some(prefix => url.pathname.startsWith(prefix))) {
        return { allowed: false, reason: '路径不在可加载范围内' }
      }
      return { allowed: true, normalizedUrl: url.toString() }
    } catch (_) {
      return { allowed: false, reason: 'URL 格式不正确' }
    }
  }
}

这个策略适合放在页面加载前。只要不允许,就进入错误页,不把风险地址交给 Web 组件。

4. BridgeGuard 给 JSBridge 做分级

JSBridge 最容易被滥用。建议把接口分为只读、用户确认、禁止三类,并对每个接口做参数约束。

export type BridgeLevel = 'READONLY' | 'CONFIRM_REQUIRED' | 'FORBIDDEN'

export interface BridgeCall {
  name: string
  payload: Record<string, Object>
  pageHost: string
}

export class BridgeGuard {
  private readonly policy: Record<string, BridgeLevel> = {
    getAppVersion: 'READONLY',
    openNativePage: 'CONFIRM_REQUIRED',
    uploadFile: 'CONFIRM_REQUIRED',
    execShell: 'FORBIDDEN'
  }

  canInvoke(call: BridgeCall): boolean {
    const level = this.policy[call.name] ?? 'FORBIDDEN'
    if (level === 'FORBIDDEN') {
      return false
    }
    if (call.name === 'openNativePage') {
      const target = call.payload['target']
      return typeof target === 'string' && target.startsWith('pages/')
    }
    return true
  }
}

接口默认禁止,显式放行。对于会跳转、上传、复制、打开原生页面的接口,建议再加用户确认或业务场景限制。

5. CookieScope 管理登录态和退出清理

混合页面经常需要登录态,但 Cookie 不能无限保留。退出登录、账号切换、隐私撤销时,Web 容器状态也要清理。

请添加图片描述

export interface CookieCleanPlan {
  host: string
  clearSession: boolean
  clearPersistent: boolean
  reason: 'logout' | 'account_switch' | 'privacy_revoke'
}

export class CookieScope {
  buildCleanPlan(reason: CookieCleanPlan['reason']): CookieCleanPlan[] {
    return [
      {
        host: 'secure.example.com',
        clearSession: true,
        clearPersistent: reason !== 'logout',
        reason
      },
      {
        host: 'help.example.com',
        clearSession: true,
        clearPersistent: false,
        reason
      }
    ]
  }
}

真实项目中清理动作要接入 ArkWeb 对应 Cookie 能力。这里强调的是策略:不同域名、不同原因,清理范围可以不同,但必须可解释。

6. FileBoundary 限制文件上传下载

Web 页面触发文件能力时,要限制类型、大小和来源。尤其是上传证件、截图、日志文件这类场景,不能直接把任意路径交给 Web。

export interface WebFileRequest {
  fileName: string
  mimeType: string
  sizeBytes: number
  source: 'camera' | 'album' | 'document'
}

export class FileBoundary {
  private readonly allowedTypes = ['image/png', 'image/jpeg', 'application/pdf']
  private readonly maxSize = 10 * 1024 * 1024

  accept(req: WebFileRequest): boolean {
    if (!this.allowedTypes.includes(req.mimeType)) {
      return false
    }
    if (req.sizeBytes <= 0 || req.sizeBytes > this.maxSize) {
      return false
    }
    return !req.fileName.toLowerCase().endsWith('.exe')
  }
}

文件边界不要只靠前端页面提示。原生层拿到文件后仍要再判断一次,避免 H5 绕过 UI 限制。

7. Web 容器错误页要可解释

加载失败、域名不可信、Bridge 被拒绝、文件不支持,都要给用户可理解提示,同时记录开发排查字段。

export interface WebErrorView {
  title: string
  description: string
  action: string
}

export function buildWebError(reason: string): WebErrorView {
  if (reason.includes('白名单') || reason.includes('域名')) {
    return { title: '页面暂不可打开', description: '当前页面来源未通过应用安全规则。', action: '返回上一页' }
  }
  if (reason.includes('文件')) {
    return { title: '文件不支持', description: '请上传图片或 PDF 文件,并确认文件大小符合要求。', action: '重新选择' }
  }
  return { title: '页面加载失败', description: '请稍后重试,或返回应用首页。', action: '重试' }
}

错误页不是掩盖问题,而是给用户一个明确出口。开发侧还要保留审计日志。

8. WebAuditLog 记录风险动作

Web 安全问题排查离不开日志。日志要记录阶段、域名、接口名、拒绝原因,但不要记录完整 Token 或敏感参数。

export interface WebAuditRecord {
  stage: 'url' | 'bridge' | 'cookie' | 'file'
  host?: string
  action: string
  result: 'allow' | 'deny'
  reason?: string
  at: number
}

export class WebAuditLog {
  private readonly records: WebAuditRecord[] = []

  append(record: Omit<WebAuditRecord, 'at'>): void {
    this.records.push({ ...record, at: Date.now() })
  }

  recentDenied(): WebAuditRecord[] {
    return this.records.filter(item => item.result === 'deny').slice(-20)
  }
}

上线后如果运营说某个活动页打不开,先看审计日志就能知道是域名、路径、桥接还是文件问题。

9. 混合容器验收动作

场景 操作 预期结果
可信活动页 加载白名单 HTTPS 地址 正常展示
非可信域名 加载外部站点 被拦截并进入错误页
Bridge 越权 H5 调用未登记接口 调用被拒绝并记录日志
账号退出 退出登录后回到 Web 页 会话 Cookie 被清理
文件上传 上传超大文件或不支持类型 被拒绝并提示原因

可以加入一个安全入口断言:

export function assertWebContainerDecision(decision: UrlDecision): void {
  if (decision.allowed && !decision.normalizedUrl?.startsWith('https://')) {
    throw new Error('允许加载的 Web 地址必须是 HTTPS')
  }
}

这个断言能防止后续修改白名单时误放行非安全协议。

10. ArkWeb 异常排查表

现象 优先查看 处理建议
页面打不开 UrlPolicy 拒绝原因、域名配置 区分域名、路径、协议问题
H5 功能无响应 Bridge 接口名、参数、策略等级 不要默认放行未知接口
退出后仍显示账号 Cookie 清理计划、账号切换事件 退登时同步清理 Web 状态
上传文件失败 文件类型、大小、来源 页面和原生层都要提示限制
审核问到隐私问题 Cookie、Bridge、文件能力说明 准备清晰的权限和数据流解释

ArkWeb 边界复现场景:给读者一组可执行核验

ArkWeb 安全要同时看域名、JSBridge、Cookie 和文件访问。只配置白名单不足以覆盖桥接调用风险。

核验维度 读者需要准备的证据
输入 页面入口、用户动作、关键参数
过程 日志、状态变化、异常分支
输出 UI 表现、回调结果、持久化结果
回归 同场景重复执行后的结果
interface ArkWebReplayCase {
  url: any
  bridgeName: any
  cookieMode: any
  fileAccess: any
}

const replay78: ArkWebReplayCase = {
  url: 'sample',
  bridgeName: 'sample',
  cookieMode: 'sample',
  fileAccess: 'sample',
}

function assertReplay78(item: ArkWebReplayCase): void {
  if (item.bridgeName && item.url.indexOf('https://') !== 0) throw new Error('非安全页面不允许桥接')
}

这组核验关注 ArkWeb 的桥接边界,适合在新增 JSBridge 或开放新域名前使用。

11. 小结:混合页面要有原生安全壳

ArkWeb 的价值是快速承载 Web 能力,但安全边界必须由原生壳掌控。URL 白名单决定能不能加载,Bridge 策略决定能不能调用原生能力,CookieScope 决定登录态如何保留和清理,FileBoundary 决定文件能否进出。把这些策略集中起来,混合页面才能既灵活又可控。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐