PHP与Flutter中SHA-256加盐哈希结果不一致求助
Flutter SHA-256加盐哈希与PHP不一致的解决方案
我在登录验证时遇到Flutter的crypto包计算SHA-256加盐哈希结果与PHP/MySQL不一致的问题:
- 密码:
Admin1234 - 盐:由PHP
random_bytes()生成的二进制数据(显示为乱码????@???R????k]?????$I"?fmP) - PHP计算结果:
d0a09d26a26196c8609d9f8ffd8a671ae0124752eea7bf338ca54f6f7f1b5e3e - Flutter计算结果:
df2a65dc4abd86afad3a6b0e30ba217fb881c23e259a3072c09480525a79216d
问题根源
PHP的random_bytes()生成的是原始二进制数据,现有Flutter代码存在两个关键问题:
- 从数据库读取salt时,将二进制数据当成字符串处理,不可打印字符被转义/乱码,丢失了原始字节信息
- 使用
Latin1Encoder()转换拼接后的字符串,但PHP是直接将密码字符串与二进制salt按原始字节拼接计算哈希,两者字节序列完全不匹配
解决方案
方案1:改用Base64编码存储盐(推荐,避免二进制存储的编码问题)
先修改PHP代码,生成盐时转成Base64字符串存储,验证时再解码回二进制:
<?php class Hash{ public static function make($string, $salt = ''){ // 将存储的Base64盐解码回二进制 $saltBytes = base64_decode($salt); return hash('sha256', $string . $saltBytes); } public static function salt($length){ // 生成二进制盐后转成Base64字符串,方便存储和传输 return base64_encode(random_bytes($length)); } public static function unique(){ return self::make(uniqid()); } } ?>
再修改Flutter代码,读取Base64盐并解码,与密码字节拼接后计算哈希:
import 'dart:convert'; import 'package:crypto/crypto.dart'; void _login(){ db.getConnection().then((conn){ String sql = 'SELECT salt FROM user WHERE email = "${username.text}"'; conn.query(sql).then((results){ if(results.isNotEmpty){ // 读取存储的Base64盐字符串 String saltBase64 = results.first[0]; // 解码成原始二进制字节 Uint8List saltBytes = base64Decode(saltBase64); String password = _password.text; // 将密码转成UTF-8字节(PHP默认用UTF-8处理字符串) Uint8List passwordBytes = utf8.encode(password); // 拼接密码字节和盐字节 Uint8List saltedBytes = Uint8List.fromList([...passwordBytes, ...saltBytes]); var digest = sha256.convert(saltedBytes); print(digest); // 现在结果与PHP一致 } else print('login failed'); }); }); }
方案2:直接存储二进制盐(需确保Flutter读取到原始二进制)
如果数据库中已存储二进制盐(比如BLOB类型),Flutter需要直接读取原始Uint8List而非字符串:
import 'dart:convert'; import 'package:crypto/crypto.dart'; void _login(){ db.getConnection().then((conn){ String sql = 'SELECT salt FROM user WHERE email = "${username.text}"'; conn.query(sql).then((results){ if(results.isNotEmpty){ // 直接获取二进制盐(需确保数据库驱动返回Uint8List,比如mysql1库对BLOB的处理) Uint8List saltBytes = results.first[0]; String password = _password.text; Uint8List passwordBytes = utf8.encode(password); Uint8List saltedBytes = Uint8List.fromList([...passwordBytes, ...saltBytes]); var digest = sha256.convert(saltedBytes); print(digest); } else print('login failed'); }); }); }
关键说明
- PHP的
hash()函数处理字符串时默认用UTF-8编码转字节,所以Flutter中要用utf8.encode()而非Latin1Encoder() - 二进制数据存储或传输时,优先用Base64编码转成字符串,避免因编码转换丢失原始字节信息
内容的提问来源于stack exchange,提问作者Muhammad Amiruddin
相关产品推荐
相关产品推荐

