
鸿蒙5安全架构实践:调用 ohos.permission.INTERNET 权限详解
一、权限声明与动态申请
- 在 module.json5 中声明权限
{
“module”: {
“requestPermissions”: [
{
“name”: “ohos.permission.INTERNET”,
“reason”: “$string:reason_internet”,
“usedScene”: {
“abilities”: [“EntryAbility”],
“when”: “inuse”
}
}
]
}
}
在资源文件中添加提示信息:
// resources/base/element/string.json
{
“string”: [
{
“name”: “reason_internet”,
“value”: “需要网络权限加载内容并更新应用”
}
]
}
2. 权限检查与动态申请
import abilityAccessCtrl from ‘@ohos.abilityAccessCtrl’;
import common from ‘@ohos.app.ability.common’;
const PERMISSION_INTERNET = ‘ohos.permission.INTERNET’;
async function checkAndRequestInternetPermission(context: common.UIAbilityContext): Promise<boolean> {
// 1. 创建AtManager实例
const atManager = abilityAccessCtrl.createAtManager();
try {
// 2. 检查权限状态
const grantStatus = await atManager.checkAccessToken(
context,
abilityAccessCtrl.PermissionState.ALL,
PERMISSION_INTERNET
);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
return true;
}
// 3. 权限未授予,进行动态申请
const requestResult = await atManager.requestPermissionsFromUser(
context,
[PERMISSION_INTERNET],
{
title: '网络访问授权',
message: '应用需要访问网络以获取最新内容',
buttonPositive: '允许',
buttonNegative: '拒绝'
}
);
return requestResult.permissions[0] === PERMISSION_INTERNET &&
requestResult.authResults[0] === 0;
} catch (err) {
console.error(权限检查错误: ${JSON.stringify(err)}
);
return false;
}
}
二、安全网络请求组件封装
下面是一个完整的安全网络请求实现,包含权限检查、HTTPS强制、数据校验等安全特性:
import http from ‘@ohos.net.http’;
import { BusinessError } from ‘@ohos.base’;
import Logger from ‘./Logger’;
const TAG = ‘SafeHttpClient’;
class SafeHttpClient {
private static readonly REQUEST_TIMEOUT = 30000; // 30秒超时
private context: common.UIAbilityContext;
constructor(context: common.UIAbilityContext) {
this.context = context;
}
// 执行安全的GET请求
public async get(url: string): Promise<any> {
if (!await this.verifyPermission()) {
throw new Error(‘网络权限未授予’);
}
return new Promise<any>(async (resolve, reject) => {
try {
// 1. 验证URL安全性
if (!this.isUrlSecure(url)) {
Logger.error(TAG, '非安全URL: ' + url);
reject('非安全URL');
return;
}
// 2. 创建HTTP请求对象
const httpRequest = http.createHttp();
// 3. 设置请求参数
const requestOptions: http.RequestOptions = {
method: http.RequestMethod.GET,
header: {
'Content-Type': 'application/json',
'X-Application-Id': 'com.example.myapp'
},
readTimeout: SafeHttpClient.REQUEST_TIMEOUT,
connectTimeout: SafeHttpClient.REQUEST_TIMEOUT,
usingCache: true,
usingProtocol: http.HttpProtocol.HTTPS,
};
Logger.info(TAG, `开始请求: ${url}`);
// 4. 发送请求
httpRequest.request(
url,
requestOptions,
async (err: BusinessError, data: http.HttpResponse) => {
try {
// 5. 错误处理
if (err) {
Logger.error(TAG, `请求错误: ${JSON.stringify(err)}`);
reject(`网络错误: ${err.code}`);
return;
}
Logger.info(TAG, `响应状态码: ${data.responseCode}`);
// 6. 检查响应状态
if (!this.isValidResponse(data)) {
reject(`无效响应: ${data.responseCode}`);
return;
}
// 7. 解析响应数据
try {
const result = typeof data.result === 'string'
? JSON.parse(data.result)
: data.result;
resolve(result);
} catch (parseErr) {
Logger.error(TAG, `JSON解析错误: ${parseErr.message}`);
reject('数据解析失败');
}
} finally {
// 8. 销毁请求对象释放资源
httpRequest.destroy();
}
}
);
} catch (error) {
Logger.error(TAG, `网络请求异常: ${error.message}`);
reject('网络请求异常');
}
});
}
// 验证网络权限
private async verifyPermission(): Promise<boolean> {
try {
const atManager = abilityAccessCtrl.createAtManager();
const grantStatus = await atManager.checkAccessToken(
this.context,
abilityAccessCtrl.PermissionState.ALL,
PERMISSION_INTERNET
);
return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
} catch (err) {
Logger.error(TAG, `权限验证错误: ${err.message}`);
return false;
}
}
// 检查URL安全性
private isUrlSecure(url: string): boolean {
// 只允许HTTPS协议
if (!url.startsWith(‘https://’)) {
return false;
}
// 禁止本地网络访问
if (/\.local$|^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/.test(url)) {
return false;
}
return true;
}
// 验证响应有效性
private isValidResponse(response: http.HttpResponse): boolean {
return response.responseCode >= http.ResponseCode.OK &&
response.responseCode < http.ResponseCode.MULTIPLE_CHOICES;
}
}
export default SafeHttpClient;
三、在Ability中使用安全网络请求
import { UIAbility } from ‘@ohos.app.ability.UIAbility’;
import { common } from ‘@ohos.app.ability.common’;
import SafeHttpClient from ‘./SafeHttpClient’;
import window from ‘@ohos.window’;
import { BusinessError } from ‘@ohos.base’;
export default class EntryAbility extends UIAbility {
private safeHttpClient: SafeHttpClient | null = null;
onCreate(want, launchParam) {
this.safeHttpClient = new SafeHttpClient(this.context);
// 检查并申请权限
this.checkAndRequestInternetPermission();
}
async checkAndRequestInternetPermission() {
const atManager = abilityAccessCtrl.createAtManager();
const grantStatus = await atManager.checkAccessToken(
this.context,
abilityAccessCtrl.PermissionState.ALL,
PERMISSION_INTERNET
);
if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
try {
await atManager.requestPermissionsFromUser(
this.context,
[PERMISSION_INTERNET],
{
title: '网络权限申请',
message: '应用需要访问网络以获取内容',
buttonPositive: '允许',
buttonNegative: '拒绝'
}
);
} catch (err) {
console.error('权限申请失败', err);
}
}
}
async onWindowStageCreate(windowStage: window.WindowStage) {
try {
windowStage.loadContent(‘pages/Index’, (err) => {
if (err) {
console.error(‘加载内容失败’, err);
}
// 加载完成后执行网络请求
this.fetchData();
});
} catch (err) {
console.error('窗口创建失败', (err as BusinessError).message);
}
}
async fetchData() {
if (!this.safeHttpClient) return;
try {
const apiUrl = 'https://api.example.com/data';
const response = await this.safeHttpClient.get(apiUrl);
// 使用安全事件机制传递数据
this.context.eventHub.emit('networkData', { data: response });
} catch (error) {
console.error('数据获取失败: ', error);
// 错误回退:使用本地缓存数据
this.context.eventHub.emit('networkData', {
data: getCachedData(),
isCached: true
});
}
}
}
四、UI组件网络数据安全展示
import { BusinessError } from ‘@ohos.base’;
@Entry
@Component
struct NetworkContentPage {
@State data: any = {};
@State isLoading: boolean = true;
@State errorMessage: string = ‘’;
private eventFunc = null;
aboutToAppear() {
// 订阅网络事件
const context = getContext(this) as common.UIAbilityContext;
this.eventFunc = context.eventHub.on(‘networkData’, (event) => {
this.isLoading = false;
if (event?.err) {
this.errorMessage = '数据加载失败: ' + event.err;
return;
}
if (event?.data) {
this.processNetworkData(event.data);
}
});
}
processNetworkData(rawData: any) {
// 1. 数据格式验证
if (!rawData || typeof rawData !== ‘object’ || Array.isArray(rawData)) {
this.errorMessage = ‘无效数据格式’;
return;
}
// 2. 清理潜在危险内容
const sanitizedData = this.sanitizeData(rawData);
// 3. 保存并展示
this.data = sanitizedData;
}
sanitizeData(data: any): any {
// 深拷贝避免修改原始数据
const result = JSON.parse(JSON.stringify(data));
// 移除脚本标签
if (result.content && typeof result.content === 'string') {
result.content = result.content.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
}
// 清理图片URL(防止XSS)
if (result.imageUrl && typeof result.imageUrl === 'string') {
result.imageUrl = result.imageUrl.replace(/[\s\'"]/g, '');
}
return result;
}
build() {
Stack() {
if (this.isLoading) {
Progress({})
.width(50)
.height(50)
.color(Color.Blue)
} else if (this.errorMessage) {
Column() {
Text(‘错误’)
.fontSize(20)
.margin({ bottom: 10 })
Text(this.errorMessage)
.fontSize(16)
.fontColor(Color.Red)
.margin({ bottom: 20 })
Button(‘重试’)
.width(‘40%’)
.onClick(() => {
this.isLoading = true;
this.context.eventHub.emit(‘retryNetwork’);
})
}
} else {
Column() {
// 展示安全处理后的数据
Text(this.data.title || ‘无标题’)
.fontSize(24)
.margin({ bottom: 15 })
Image(this.data.imageUrl)
.width('90%')
.height(200)
.objectFit(ImageFit.Contain)
.borderRadius(8)
.margin({ bottom: 15 })
Text(this.data.content || '无内容')
.fontSize(16)
}
.padding(16)
}
}
.onPageHide(() => {
// 取消事件订阅
if (this.eventFunc) {
const context = getContext(this) as common.UIAbilityContext;
context.eventHub.off('networkData', this.eventFunc);
}
})
}
}
五、高级网络安全实践
- 网络安全配置
在resources/rawfile/network_security_config.json中:
{
“cleartextTrafficPermitted”: false,
“domainConfig”: {
“domains”: [
{
“name”: “api.example.com”,
“includeSubdomains”: true,
“certificates”: [
{
“src”: “@rawfile/api.example.com.crt”
}
]
}
]
}
}
2. 使用证书绑定增强安全
import ssl from ‘@ohos.security.cert’;
const API_HOST = ‘api.example.com’;
const PINNED_CERT_SHA256 = ‘CERT_SHA256_VALUE’;
async function verifyCertificate(host: string, cert: ArrayBuffer): Promise<boolean> {
try {
// 1. 创建证书对象
const certObj = ssl.X509.createX509(cert);
// 2. 检查主体名称
const subject = certObj.getSubjectName();
if (!subject.includes(API_HOST)) {
return false;
}
// 3. 计算证书哈希
const certHash = await cryptoFramework.hash.createHash(cryptoFramework.Hash.SHA256);
await certHash.update(cert);
const hashResult = await certHash.digest();
// 4. 比较哈希值
return PINNED_CERT_SHA256 === bytesToHex(hashResult);
} catch (err) {
console.error(‘证书验证失败’, err);
return false;
}
}
function bytesToHex(bytes: Uint8Array): string {
return Array.from(bytes)
.map(b => b.toString(16).padStart(2, ‘0’))
.join(‘:’)
.toUpperCase();
}
3. 实施网络状态监控
import network from ‘@ohos.net.network’;
import common from ‘@ohos.app.ability.common’;
class NetworkMonitor {
private context: common.UIAbilityContext;
private netConnection: netConnection.NetConnection | null = null;
private listeners: Array<(isConnected: boolean) => void> = [];
constructor(context: common.UIAbilityContext) {
this.context = context;
this.initNetworkMonitoring();
}
initNetworkMonitoring() {
try {
const netSpecifier: netConnection.NetSpecifier = {
capabilities: {
bearerTypes: [netConnection.NetBearType.BEARER_CELLULAR,
netConnection.NetBearType.BEARER_WIFI]
}
};
this.netConnection = network.createNetConnection(netSpecifier);
this.netConnection.on('netAvailable', () => {
this.notifyListeners(true);
});
this.netConnection.on('netUnavailable', () => {
this.notifyListeners(false);
});
this.netConnection.on('netCapabilitiesChange', () => {
// 可做更精细处理
});
this.netConnection.register();
} catch (err) {
console.error('网络监控初始化失败', err);
}
}
addListener(listener: (isConnected: boolean) => void) {
this.listeners.push(listener);
}
private notifyListeners(isConnected: boolean) {
this.listeners.forEach(listener => listener(isConnected));
}
release() {
if (this.netConnection) {
this.netConnection.unregister();
this.netConnection = null;
}
}
}
六、安全防护全面方案
- 防护矩阵总结
防护层级 安全措施
权限控制 动态权限申请、权限状态监听
传输安全 HTTPS强制、证书固定、网络安全配置
数据安全 响应校验、内容清理、SQL注入防护
应用层防护 请求签名、请求频率限制、设备指纹
防御机制 异常处理、连接池隔离、错误日志脱敏 - 安全加固代码示例
// 安全HTTP头配置
const SECURE_HEADERS = {
‘Content-Security-Policy’: “default-src ‘self’; img-src *; media-src media1.com media2.com; script-src userscripts.example.com”,
‘X-Frame-Options’: ‘SAMEORIGIN’,
‘X-Content-Type-Options’: ‘nosniff’,
‘Referrer-Policy’: ‘strict-origin-when-cross-origin’
};
// 增强型请求方法
async function enhancedGetWithRetry(url: string, retries = 2, delay = 1000): Promise<any> {
try {
const response = await safeHttpClient.get(url);
return response;
} catch (error) {
if (retries > 0) {
await new Promise(resolve => setTimeout(resolve, delay));
return enhancedGetWithRetry(url, retries - 1, delay * 2);
}
throw error;
}
}
// 速率限制器
class RateLimiter {
private requests: Map<string, number> = new Map();
allowRequest(ip: string, max: number, windowMs: number): boolean {
const now = Date.now();
const key = rate_limit:${ip}
;
if (!this.requests.has(key)) {
this.requests.set(key, 0);
setTimeout(() => this.requests.delete(key), windowMs);
}
const count = this.requests.get(key) || 0;
if (count >= max) {
return false;
}
this.requests.set(key, count + 1);
return true;
}
}
七、总结与最佳实践
在鸿蒙5中安全使用 ohos.permission.INTERNET 权限需遵循以下最佳实践:
最小权限原则:仅在必要时请求权限
动态权限处理:使用createAtManager进行权限检查与申请
传输层安全:强制使用HTTPS + 证书绑定
安全数据处理:实现严格输入输出验证和清理
防御性编程:添加速率限制、错误处理和重试机制
隐私保护:最小化数据传输,使用令牌代替敏感信息
持续监控:实施网络状态实时检测和安全审计
通过本文的完整实现方案,开发者可以构建出符合鸿蒙安全架构规范的应用,有效防止中间人攻击、数据泄漏、权限滥用等安全风险,为用户提供安全可靠的网络访问体验。
