【OpenHarmony/HarmonyOs 】安全打开网页:Axios HTTPS 拦截、URL 检测与 ArkWeb 容器
【OpenHarmony/HarmonyOs 】安全打开网页:Axios HTTPS 拦截、URL 检测与 ArkWeb 容器
前言
导航类应用最重要的边界是外部链接。一个 URL 从用户输入到显示网页,至少要经过协议规范化、网络策略、安全判断、路由传参和 WebView 加载。任何入口绕过其中一步,都可能形成风险。本文给出 LinkOS 链界当前实现,并说明生产环境还需要补齐什么。🔐
一、第一层:网络请求统一强制 HTTPS
项目基于 @ohos/axios 创建共享实例,并设置 8 秒超时:
private static readonly TIMEOUT = 8000;
HttpUtil.instance = axios.create({
timeout: HttpUtil.TIMEOUT,
headers: { 'Content-Type': 'application/json' }
});
请求拦截器阻止非 HTTPS 地址:
HttpUtil.instance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
if (config.url && !config.url.startsWith('https://')) {
console.error('[HttpUtil] Non-HTTPS blocked:', config.url);
return Promise.reject(new Error('Only HTTPS requests are allowed'));
}
return config;
}
);
统一实例的优势在于:搜索建议、天气、云函数等请求都会自动遵守相同策略。以后增加 Token、Trace ID、统一错误映射,也只需改一处。
二、第二层:区分超时与断网
HttpUtil.instance.interceptors.response.use(
response => response,
(error: AxiosError) => {
if (error.code === 'ECONNABORTED') {
console.error('[HttpUtil] Request timeout');
} else if (error.message?.includes('Network Error')) {
console.error('[HttpUtil] Network error');
}
return Promise.reject(error);
}
);
网络错误不应全部显示“请求失败”。超时、无网络、证书错误、401 与服务器 500 对用户和排查者的意义不同。建议进一步定义领域错误,例如 TIMEOUT、OFFLINE、AUTH_EXPIRED,页面只负责将错误映射为合适提示。
三、第三层:打开前执行 URL 安全检测
private async openUrl(url: string): Promise<void> {
const safe = await SecurityUtil.checkUrlSafety(url);
if (!safe) {
AlertDialog.show({
title: '风险提示',
message: `该网站 (${url}) 可能包含恶意内容,已拦截。`,
confirm: { value: '知道了', action: () => {} }
});
return;
}
router.pushUrl({
url: 'pages/v2/WebViewPage',
params: { url }
});
}
项目中的 SecurityUtil 目前是模拟实现:要求 URL 以 HTTPS 开头、提取 hostname,并对本地黑名单检查。它适合演示调用链,但不能等同于真实安全能力。
生产环境至少要防范:
- 钓鱼与恶意域名;
- Unicode 相似字符域名;
- 重定向后跳到 HTTP 或危险 Scheme;
javascript:、file:等不期望协议;- 证书异常与中间人攻击;
- URL 中携带的敏感 Token 被记录到日志。
四、域名匹配不能使用简单 includes
示例中黑名单使用 hostname.includes(domain)。这会让 notmalicious.com 也可能命中 malicious.com。更严谨的域名边界判断是:
function matchesDomain(host: string, domain: string): boolean {
return host === domain || host.endsWith(`.${domain}`);
}
此外,正则提取 hostname 适合受控输入;面对完整 URL 标准时,应优先使用平台提供的 URI/URL 解析能力,避免自行解析遗漏边界。
五、ArkWeb 页面接收路由参数
@Entry
@Component
struct WebViewPage {
controller: webview.WebviewController = new webview.WebviewController();
@State url: string = '';
@State title: string = '加载中...';
@State progress: number = 0;
aboutToAppear() {
const params = router.getParams() as Record<string, string>;
if (params && params['url']) {
this.url = params['url'];
}
}
}
WebviewController 用于后续控制前进、后退、刷新等行为;路由参数只负责传递目标地址。页面进入时仍建议再次验证参数,实现“纵深防御”,不要完全相信上一个页面。
六、标题和进度构成基础浏览体验
Web({ src: this.url, controller: this.controller })
.width('100%')
.layoutWeight(1)
.onTitleReceive(event => {
if (event) this.title = event.title;
})
.onProgressChange(event => {
if (event) this.progress = event.newProgress;
});
加载进度小于 100 时展示 Progress,收到网页标题后更新顶部栏。即使只是一个最小 Web 容器,这两个反馈也能显著降低用户对“页面卡住”的误判。
完整浏览器容器还应实现:
- WebView 内部返回历史,历史为空再退出页面;
- 加载失败页与重试按钮;
- 顶部域名显示和证书风险提示;
- 下载、文件选择、权限请求策略;
- 新窗口与外部 Scheme 拦截;
- 页面销毁时资源释放;
- JavaScript Bridge 最小权限和来源校验。
七、不要把 API Key 放进客户端
项目计划接入 AI 服务,这里必须强调:HAP 最终运行在用户设备上,任何硬编码 Key 都能被提取。正确链路应是:
HarmonyOS 客户端
↓ 用户身份令牌 + HTTPS
AGC Cloud Function
↓ 服务端保管密钥、限流、审计
第三方 AI API
客户端只接触自己的短期身份凭证,不接触供应商密钥。云函数还应校验用户、限制请求频率并过滤日志中的敏感字段。
八、总结
网页安全不是一个 startsWith('https://') 就能完成,而是多层防线:输入规范化、统一请求拦截、域名安全服务、重定向检查、WebView 导航拦截与服务端密钥隔离。当前项目已经搭出完整链路骨架,下一阶段应把模拟检测替换为真实安全服务,并补齐 WebView 内部导航策略。🛡️

更多推荐
所有评论(0)