寻求Flutter与Ruby on Rails后端兼容的AES加解密方案
Flutter与Ruby on Rails间AES加密数据传输实现方案
核心约定
统一使用AES-256-CBC模式,PKCS7填充,密钥为32字节(256位),每次加密生成随机16字节IV(初始化向量),IV随密文一同传输(无需加密)。
Flutter 端实现
使用encrypt包处理加密逻辑,配合flutter_secure_storage安全存储密钥(避免硬编码)。
- 添加依赖到
pubspec.yaml:
dependencies: encrypt: ^5.0.1 flutter_secure_storage: ^8.0.0
- 加密/解密工具类示例:
import 'package:encrypt/encrypt.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class AesCrypto { static final _storage = FlutterSecureStorage(); static late Key _key; static final _ivLength = 16; // 初始化密钥(从安全存储读取,首次启动需从后端安全获取后存入) static Future<void> initKey() async { String? keyStr = await _storage.read(key: 'aes_secret_key'); if (keyStr == null) { // 示例用固定密钥,实际需从后端安全获取后存入secure storage keyStr = 'your_32_byte_secure_secret_key_here_1234'; await _storage.write(key: 'aes_secret_key', value: keyStr); } _key = Key.fromUtf8(keyStr); } // 加密数据:返回格式为 [IV base64]:[密文 base64] static Future<String> encrypt(String plainText) async { await initKey(); final iv = IV.fromSecureRandom(_ivLength); final encrypter = Encrypter(AES(_key, mode: AESMode.cbc, padding: 'PKCS7')); final encrypted = encrypter.encrypt(plainText, iv: iv); return '${iv.base64}:${encrypted.base64}'; } // 解密数据:拆分IV和密文后解密 static Future<String> decrypt(String encryptedText) async { await initKey(); final parts = encryptedText.split(':'); final iv = IV.fromBase64(parts[0]); final encrypted = Encrypted.fromBase64(parts[1]); final encrypter = Encrypter(AES(_key, mode: AESMode.cbc, padding: 'PKCS7')); return encrypter.decrypt(encrypted, iv: iv); } }
- 请求时加密敏感字段:
// 示例:加密密码后发送 String encryptedPwd = await AesCrypto.encrypt('user_plain_password'); var response = await http.post( Uri.parse('https://your-rails-api.com/login'), body: { 'user_id': 'user123', // user_id需加密时同样调用encrypt方法 'encrypted_password': encryptedPwd, }, );
Ruby on Rails 端实现
Ruby自带OpenSSL库,无需额外gem,实现与Flutter端参数完全一致的加密/解密逻辑。
- 加密/解密工具类(可放在
lib/aes_crypto.rb):
require 'openssl' require 'base64' class AesCrypto AES_MODE = 'CBC' AES_PADDING = 'PKCS7' KEY_LENGTH = 32 # 256位 class << self # 从环境变量读取密钥,避免硬编码 def secret_key ENV['AES_SECRET_KEY'] || 'your_32_byte_secure_secret_key_here_1234' end # 解密Flutter传来的加密字符串 def decrypt(encrypted_text) iv_base64, ciphertext_base64 = encrypted_text.split(':') iv = Base64.decode64(iv_base64) ciphertext = Base64.decode64(ciphertext_base64) cipher = OpenSSL::Cipher.new("AES-#{KEY_LENGTH*8}-#{AES_MODE}") cipher.decrypt cipher.key = secret_key cipher.iv = iv cipher.padding = OpenSSL::Cipher::PKCS7_PADDING cipher.update(ciphertext) + cipher.final end # 加密数据(后端给Flutter返回敏感数据时使用) def encrypt(plain_text) cipher = OpenSSL::Cipher.new("AES-#{KEY_LENGTH*8}-#{AES_MODE}") cipher.encrypt cipher.key = secret_key iv = cipher.random_iv ciphertext = cipher.update(plain_text) + cipher.final "#{Base64.encode64(iv).strip}:#{Base64.encode64(ciphertext).strip}" end end end
- 在控制器中使用解密逻辑:
# 示例:登录接口解密密码 class SessionsController < ApplicationController def create user_id = params[:user_id] encrypted_pwd = params[:encrypted_password] plain_password = AesCrypto.decrypt(encrypted_pwd) # 后续验证逻辑:根据user_id和plain_password查找用户等 user = User.find_by(id: user_id) if user&.authenticate(plain_password) render json: { status: 'success', token: generate_jwt(user) } else render json: { status: 'error', message: 'Invalid credentials' }, status: :unauthorized end end end
- 配置密钥:在
.env文件中添加(配合dotenv-railsgem):
AES_SECRET_KEY=your_32_byte_secure_secret_key_here_1234
关键注意事项
- 密钥安全:绝对不能硬编码密钥,Flutter端用安全存储,ROR端用环境变量,首次分发密钥需通过HTTPS请求完成,避免明文传输密钥。
- HTTPS不可替代:AES加密是敏感字段的额外防护,必须配合HTTPS使用,防止中间人攻击窃取加密后的密文或IV。
- IV必须随机:每次加密都要生成新的随机IV,避免相同明文加密后产生相同密文,降低被破解风险。
内容的提问来源于stack exchange,提问作者Prashant
相关产品推荐
相关产品推荐

