uni-app数据加密:跨端敏感信息保护

uni-app数据加密:跨端敏感信息保护

【免费下载链接】uni-app A cross-platform framework using Vue.js 【免费下载链接】uni-app 项目地址: https://gitcode.com/dcloud/uni-app

前言:移动应用数据安全的严峻挑战

在移动应用开发中,数据安全一直是开发者面临的核心挑战。随着uni-app跨端开发框架的普及,如何在多个平台(微信小程序、支付宝小程序、App、H5等)上统一实现敏感信息的保护,成为了开发者必须面对的技术难题。

你是否曾经遇到过这些问题?

  • 用户登录凭证在本地存储中被轻易获取
  • 敏感配置信息在代码中明文暴露
  • 不同平台的安全机制差异导致加密方案难以统一
  • 加解密性能影响用户体验

本文将为你全面解析uni-app中的数据加密最佳实践,帮助你构建安全可靠的跨端应用。

uni-app数据存储安全架构

mermaid

核心加密方案实现

1. 基础加密工具类

首先创建一个统一的加密工具类,支持多种加密算法:

// utils/crypto.js
import { md5, sha256 } from 'crypto-js'
import AES from 'crypto-js/aes'
import Base64 from 'crypto-js/enc-base64'
import Utf8 from 'crypto-js/enc-utf8'

class UniAppCrypto {
  constructor() {
    this.key = this.generateAppKey()
    this.iv = this.generateIV()
  }

  // 生成应用唯一密钥
  generateAppKey() {
    // 结合设备信息和应用特征生成唯一密钥
    const deviceInfo = uni.getSystemInfoSync()
    const appInfo = require('../package.json')
    
    const rawKey = `${deviceInfo.platform}-${deviceInfo.model}-${appInfo.version}`
    return sha256(rawKey).toString().substring(0, 32)
  }

  generateIV() {
    return md5(Date.now().toString()).toString().substring(0, 16)
  }

  // AES加密
  encryptAES(data) {
    try {
      if (typeof data === 'object') {
        data = JSON.stringify(data)
      }
      const encrypted = AES.encrypt(data, this.key, { 
        iv: this.iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      })
      return encrypted.toString()
    } catch (error) {
      console.error('AES加密失败:', error)
      return null
    }
  }

  // AES解密
  decryptAES(encryptedData) {
    try {
      const decrypted = AES.decrypt(encryptedData, this.key, {
        iv: this.iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      })
      const result = decrypted.toString(Utf8)
      
      // 尝试解析JSON
      try {
        return JSON.parse(result)
      } catch {
        return result
      }
    } catch (error) {
      console.error('AES解密失败:', error)
      return null
    }
  }

  // 哈希函数
  hashMD5(data) {
    return md5(data).toString()
  }

  hashSHA256(data) {
    return sha256(data).toString()
  }

  // Base64编码解码
  base64Encode(data) {
    return Base64.stringify(Utf8.parse(data))
  }

  base64Decode(encoded) {
    return Base64.parse(encoded).toString(Utf8)
  }
}

export default new UniAppCrypto()

2. 安全存储封装

对uni-app的存储API进行安全封装:

// utils/secureStorage.js
import crypto from './crypto'

class SecureStorage {
  // 加密存储
  setItem(key, value, encrypt = true) {
    try {
      let storageValue = value
      
      if (encrypt) {
        storageValue = crypto.encryptAES(value)
        if (!storageValue) {
          throw new Error('加密失败')
        }
      }
      
      uni.setStorageSync(key, storageValue)
      return true
    } catch (error) {
      console.error('安全存储失败:', error)
      return false
    }
  }

  // 解密读取
  getItem(key, decrypt = true) {
    try {
      const encryptedValue = uni.getStorageSync(key)
      
      if (encryptedValue === null || encryptedValue === undefined) {
        return null
      }
      
      if (decrypt) {
        return crypto.decryptAES(encryptedValue)
      }
      
      return encryptedValue
    } catch (error) {
      console.error('安全读取失败:', error)
      return null
    }
  }

  // 批量加密存储
  setMultiple(items, encrypt = true) {
    const results = {}
    
    Object.keys(items).forEach(key => {
      results[key] = this.setItem(key, items[key], encrypt)
    })
    
    return results
  }

  // 删除项
  removeItem(key) {
    try {
      uni.removeStorageSync(key)
      return true
    } catch (error) {
      console.error('删除存储项失败:', error)
      return false
    }
  }

  // 清空存储
  clear() {
    try {
      uni.clearStorageSync()
      return true
    } catch (error) {
      console.error('清空存储失败:', error)
      return false
    }
  }
}

export default new SecureStorage()

3. 跨平台安全适配器

// utils/securityAdapter.js
class SecurityAdapter {
  constructor() {
    this.platform = uni.getSystemInfoSync().platform
    this.securityLevel = this.getSecurityLevel()
  }

  getSecurityLevel() {
    const levels = {
      'android': 'high',     // Android提供硬件级加密
      'ios': 'high',         // iOS有Keychain保护
      'devtools': 'low',     // 开发工具环境
      'windows': 'medium',   // Windows平台
      'mac': 'medium',       // Mac平台
    }
    
    return levels[this.platform] || 'medium'
  }

  // 平台特定的加密增强
  enhanceEncryption(data, context = 'storage') {
    switch (this.platform) {
      case 'android':
        return this.androidEncrypt(data, context)
      case 'ios':
        return this.iosEncrypt(data, context)
      default:
        return data
    }
  }

  androidEncrypt(data, context) {
    // Android平台使用硬件加密增强
    if (context === 'storage' && this.securityLevel === 'high') {
      // 添加Android特有的安全标记
      return {
        _android_secure: true,
        _timestamp: Date.now(),
        data: data
      }
    }
    return data
  }

  iosEncrypt(data, context) {
    // iOS平台使用Keychain相关增强
    if (context === 'storage' && this.securityLevel === 'high') {
      return {
        _ios_secure: true,
        _keychain_compatible: true,
        data: data
      }
    }
    return data
  }

  // 安全传输配置
  getSecurityHeaders() {
    return {
      'X-Security-Level': this.securityLevel,
      'X-Platform': this.platform,
      'X-Timestamp': Date.now(),
      'X-Request-ID': this.generateRequestId()
    }
  }

  generateRequestId() {
    return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
  }
}

export default new SecurityAdapter()

实战应用场景

场景1:用户登录凭证保护

// services/authService.js
import secureStorage from '@/utils/secureStorage'
import crypto from '@/utils/crypto'

class AuthService {
  // 安全存储登录令牌
  async secureLogin(credentials) {
    try {
      const response = await uni.request({
        url: '/api/auth/login',
        method: 'POST',
        data: {
          username: credentials.username,
          password: crypto.hashSHA256(credentials.password),
          deviceId: this.getDeviceId()
        },
        header: {
          'Content-Type': 'application/json',
          ...securityAdapter.getSecurityHeaders()
        }
      })
      
      if (response.data.success) {
        // 加密存储token和用户信息
        const authData = {
          token: response.data.token,
          refreshToken: response.data.refreshToken,
          userInfo: response.data.user,
          expiresAt: Date.now() + response.data.expiresIn * 1000
        }
        
        secureStorage.setItem('auth_data', authData)
        secureStorage.setItem('last_login', Date.now())
        
        return { success: true, data: authData }
      }
      
      return { success: false, error: response.data.message }
    } catch (error) {
      console.error('登录失败:', error)
      return { success: false, error: '网络错误' }
    }
  }

  // 获取设备唯一标识
  getDeviceId() {
    const systemInfo = uni.getSystemInfoSync()
    const appInfo = require('@/package.json')
    
    const deviceData = {
      platform: systemInfo.platform,
      model: systemInfo.model,
      version: systemInfo.version,
      appVersion: appInfo.version
    }
    
    return crypto.hashSHA256(JSON.stringify(deviceData))
  }

  // 检查登录状态
  checkAuthStatus() {
    const authData = secureStorage.getItem('auth_data')
    
    if (!authData || !authData.token) {
      return false
    }
    
    // 检查token是否过期
    if (authData.expiresAt < Date.now()) {
      this.refreshToken()
      return false
    }
    
    return true
  }

  // token刷新
  async refreshToken() {
    const authData = secureStorage.getItem('auth_data')
    
    if (!authData || !authData.refreshToken) {
      this.logout()
      return
    }
    
    try {
      const response = await uni.request({
        url: '/api/auth/refresh',
        method: 'POST',
        data: {
          refreshToken: authData.refreshToken
        },
        header: securityAdapter.getSecurityHeaders()
      })
      
      if (response.data.success) {
        authData.token = response.data.token
        authData.expiresAt = Date.now() + response.data.expiresIn * 1000
        
        secureStorage.setItem('auth_data', authData)
      } else {
        this.logout()
      }
    } catch (error) {
      console.error('token刷新失败:', error)
      this.logout()
    }
  }

  // 安全退出
  logout() {
    secureStorage.removeItem('auth_data')
    secureStorage.removeItem('last_login')
    // 其他清理操作...
  }
}

export default new AuthService()

场景2:敏感配置信息保护

// config/secureConfig.js
import crypto from '@/utils/crypto'
import secureStorage from '@/utils/secureStorage'

// 敏感配置项
const SENSITIVE_CONFIG = {
  apiKeys: {
    map: 'your_map_api_key',
    push: 'your_push_service_key',
    analytics: 'your_analytics_key'
  },
  endpoints: {
    auth: 'https://api.example.com/auth',
    payment: 'https://api.example.com/payment'
  },
  security: {
    encryptionKey: 'default_encryption_key_backup'
  }
}

class SecureConfig {
  constructor() {
    this.config = {}
    this.loadConfig()
  }

  // 加载并解密配置
  loadConfig() {
    // 尝试从安全存储加载
    const storedConfig = secureStorage.getItem('app_config')
    
    if (storedConfig) {
      this.config = storedConfig
    } else {
      // 首次运行,加密存储默认配置
      this.config = this.encryptConfig(SENSITIVE_CONFIG)
      secureStorage.setItem('app_config', this.config)
    }
  }

  encryptConfig(config) {
    const encrypted = { ...config }
    
    // 对敏感字段进行加密
    if (encrypted.apiKeys) {
      Object.keys(encrypted.apiKeys).forEach(key => {
        encrypted.apiKeys[key] = crypto.encryptAES(encrypted.apiKeys[key])
      })
    }
    
    if (encrypted.security && encrypted.security.encryptionKey) {
      encrypted.security.encryptionKey = crypto.encryptAES(
        encrypted.security.encryptionKey
      )
    }
    
    return encrypted
  }

  // 获取解密后的配置值
  get(keyPath, defaultValue = null) {
    const keys = keyPath.split('.')
    let value = this.config
    
    for (const key of keys) {
      if (value && typeof value === 'object' && key in value) {
        value = value[key]
      } else {
        return defaultValue
      }
    }
    
    // 如果是加密的值,尝试解密
    if (typeof value === 'string' && value.length > 50) {
      try {
        const decrypted = crypto.decryptAES(value)
        return decrypted || defaultValue
      } catch {
        return defaultValue
      }
    }
    
    return value || defaultValue
  }

  // 更新配置
  update(keyPath, value) {
    const keys = keyPath.split('.')
    let config = this.config
    
    for (let i = 0; i < keys.length - 1; i++) {
      const key = keys[i]
      if (!config[key] || typeof config[key] !== 'object') {
        config[key] = {}
      }
      config = config[key]
    }
    
    const lastKey = keys[keys.length - 1]
    
    // 对敏感字段自动加密
    if (keyPath.includes('apiKeys') || keyPath.includes('security')) {
      config[lastKey] = crypto.encryptAES(value)
    } else {
      config[lastKey] = value
    }
    
    // 保存更新后的配置
    secureStorage.setItem('app_config', this.config)
  }
}

export default new SecureConfig()

性能优化与最佳实践

加密性能优化策略

mermaid

代码实现示例

// utils/performanceCrypto.js
import crypto from './crypto'

class PerformanceCrypto {
  constructor() {
    this.cache = new Map()
    this.cacheTimeout = 5 * 60 * 1000 // 5分钟缓存
  }

  // 带缓存的加密
  encryptWithCache(key, data, forceUpdate = false) {
    const cacheKey = `encrypt_${key}`
    
    if (!forceUpdate) {
      const cached = this.getFromCache(cacheKey)
      if (cached) {
        return cached
      }
    }
    
    const encrypted = crypto.encryptAES(data)
    this.setToCache(cacheKey, encrypted)
    
    return encrypted
  }

  // 带缓存的解密
  decryptWithCache(encryptedData, originalKey) {
    const cacheKey = `decrypt_${originalKey}`
    const cached = this.getFromCache(cacheKey)
    
    if (cached) {
      return cached
    }
    
    const decrypted = crypto.decryptAES(encryptedData)
    this.setToCache(cacheKey, decrypted)
    
    return decrypted
  }

  getFromCache(key) {
    const item = this.cache.get(key)
    if (item && Date.now() - item.timestamp < this.cacheTimeout) {
      return item.data
    }
    return null
  }

  setToCache(key, data) {
    this.cache.set(key, {
      data: data,
      timestamp: Date.now()
    })
  }

  // 清空缓存
  clearCache() {
    this.cache.clear()
  }

  // 批量加密优化
  batchEncrypt(items) {
    const results = {}
    const promises = []
    
    Object.keys(items).forEach(key => {
      promises.push(
        new Promise(resolve => {
          setTimeout(() => {
            results[key] = this.encryptWithCache(key, items[key])
            resolve()
          }, 0)
        })
      )
    })
    
    return Promise.all(promises).then(() => results)
  }
}

export default new PerformanceCrypto()

安全检测与监控

运行时安全检测

// utils/securityMonitor.js
class SecurityMonitor {
  constructor() {
    this.threatsDetected = 0
    this.lastCheckTime = Date.now()
    this.setupMonitoring()
  }

  setupMonitoring() {
    // 定时安全检查
    setInterval(() => {
      this.runSecurityChecks()
    }, 30000) // 每30秒检查一次

    // 监听存储变化
    this.setupStorageMonitoring()
  }

  runSecurityChecks() {
    this.checkDebugMode()
    this.checkStorageTampering()
    this.checkNetworkSecurity()
  }

  checkDebugMode() {
    // 检查是否处于调试模式
    try {

【免费下载链接】uni-app A cross-platform framework using Vue.js 【免费下载链接】uni-app 项目地址: https://gitcode.com/dcloud/uni-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值