鸿蒙5安全架构实践:调用 ohos.permission.INTERNET 权限详解

暗雨OL
发布于 2025-6-27 22:01
浏览
0收藏

一、权限声明与动态申请

  1. 在 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);
  }
})

}
}
五、高级网络安全实践

  1. 网络安全配置
    在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;
}
}
}
六、安全防护全面方案

  1. 防护矩阵总结
    防护层级 安全措施
    ​​权限控制​​ 动态权限申请、权限状态监听
    ​​传输安全​​ HTTPS强制、证书固定、网络安全配置
    ​​数据安全​​ 响应校验、内容清理、SQL注入防护
    ​​应用层防护​​ 请求签名、请求频率限制、设备指纹
    ​​防御机制​​ 异常处理、连接池隔离、错误日志脱敏
  2. 安全加固代码示例
    // 安全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 + 证书绑定
​​安全数据处理​​:实现严格输入输出验证和清理
​​防御性编程​​:添加速率限制、错误处理和重试机制
​​隐私保护​​:最小化数据传输,使用令牌代替敏感信息
​​持续监控​​:实施网络状态实时检测和安全审计
通过本文的完整实现方案,开发者可以构建出符合鸿蒙安全架构规范的应用,有效防止中间人攻击、数据泄漏、权限滥用等安全风险,为用户提供安全可靠的网络访问体验。

分类
标签
收藏
回复
举报
回复
    相关推荐