You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何安全存储与检索自定义图案锁屏?

Flutter 安全存储与检索图案锁方案

核心原则:绝不存储明文

Shared Preferences 默认是明文存储,直接存图案会有被恶意读取的风险,所以必须先加密再存储,优先使用系统级安全存储方案。


方案一:使用 flutter_secure_storage(推荐)

这个插件会利用系统自带的安全存储(Android Keystore、iOS Keychain),比自行加密更可靠。

步骤:

  1. 添加依赖
    在 pubspec.yaml 中加入:
dependencies:
  flutter_secure_storage: ^9.0.0 # 替换为最新版本
  1. 初始化存储实例
final secureStorage = FlutterSecureStorage();
  1. 存储图案
    把图案序列转成字符串后存储:
// 假设pattern是用户设置的图案,比如List<int> pattern = [0,1,2,4]
Future<void> savePatternLock(List<int> pattern) async {
  String patternStr = pattern.join(',');
  await secureStorage.write(key: 'app_pattern_lock', value: patternStr);
}
  1. 检索图案
    读取后转回序列:
Future<List<int>?> getPatternLock() async {
  String? storedPatternStr = await secureStorage.read(key: 'app_pattern_lock');
  if (storedPatternStr != null) {
    return storedPatternStr.split(',').map(int.parse).toList();
  }
  return null;
}

方案二:加密后存入 Shared Preferences

如果坚持用 Shared Preferences,必须配合加密插件(比如 encrypt)处理。

步骤:

  1. 添加依赖
dependencies:
  shared_preferences: ^2.2.2 # 最新版本
  encrypt: ^5.0.1 # 最新版本
  crypto: ^3.0.3 # 用于恒定时间比较,避免时序攻击
  1. 加密存储逻辑
import 'package:encrypt/encrypt.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:crypto/crypto.dart';

// 建议将密钥存在flutter_secure_storage中,避免硬编码
final key = Key.fromSecureRandom(32);
final iv = IV.fromSecureRandom(16);
final encrypter = Encrypter(AES(key));

// 存储加密后的图案
Future<void> saveEncryptedPattern(List<int> pattern) async {
  final prefs = await SharedPreferences.getInstance();
  String patternStr = pattern.join(',');
  String encrypted = encrypter.encrypt(patternStr, iv: iv).base64;
  await prefs.setString('encrypted_pattern', encrypted);
  await prefs.setString('pattern_iv', iv.base64); // IV可明文存储
}

// 解密并获取图案
Future<List<int>?> getEncryptedPattern() async {
  final prefs = await SharedPreferences.getInstance();
  String? encrypted = prefs.getString('encrypted_pattern');
  String? ivStr = prefs.getString('pattern_iv');
  
  if (encrypted != null && ivStr != null) {
    final iv = IV.fromBase64(ivStr);
    String decrypted = encrypter.decrypt(Encrypted.fromBase64(encrypted), iv: iv);
    return decrypted.split(',').map(int.parse).toList();
  }
  return null;
}
  1. 安全对比图案
    避免时序攻击,用恒定时间比较:
bool isPatternMatch(List<int> input, List<int> stored) {
  if (input.length != stored.length) return false;
  var inputBytes = utf8.encode(input.join(','));
  var storedBytes = utf8.encode(stored.join(','));
  return constantTimeEquals(inputBytes, storedBytes);
}

应用启动时的校验逻辑

在 main 函数中检查是否有已存储的图案,决定跳转页面:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  List<int>? storedPattern = await getPatternLock(); // 或getEncryptedPattern()
  
  runApp(MaterialApp(
    home: storedPattern != null ? PatternLockVerifyScreen() : HomeScreen(),
  ));
}

内容的提问来源于stack exchange,提问作者Saurabh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:11:34