不能安全存储用户密码凭证,应避免使用uni.setStorageSync明文存密码;必须存时须用AES加密+设备绑定密钥,并配合服务端风控与token鉴权机制。

不能安全存储用户密码凭证——这是前提。任何客户端本地存储的密码(包括加密后)都存在被逆向、调试、内存 dump 或物理访问提取的风险。真正该做的是:不存密码,只存 token;必须存凭证时,只存经过强加密处理的最小必要信息,并配合服务端风控。
uni.setStorageSync 存密码明文就是高危操作
直接用 uni.setStorageSync('password', this.password) 是最常见也最危险的做法。Android 10+ 分区存储虽限制了外部路径访问,但 uni.setStorageSync 写入的是应用私有 SQLite 数据库(uniapp_storage),只要设备已 root 或被安装恶意调试工具,就能直接导出并读取全部键值对。微信小程序虽有 sandbox 隔离,但开发者工具、抓包插件、甚至部分越狱 iOS 设备仍可绕过。
- 明文密码一旦泄露,等于账号完全失守,且用户大概率在多个平台复用同一密码
-
uni.getStorageSync返回的是字符串,没有任何访问权限控制或生命周期管理 - 该 API 不提供加密能力,也不校验调用上下文(比如是否在生物识别通过后才允许读取)
token 替代密码 + httpOnly cookie 是更合理的方案
登录成功后,后端应返回短期有效的 access_token(JWT 或 opaque token),前端只存储这个 token,并用它后续所有请求鉴权。这才是现代认证的标准实践。
- token 应设为短期有效(如 2 小时),配合 refresh_token 实现静默续期
- 若后端支持,优先使用
httpOnly+Securecookie(H5 环境下),前端 JS 无法读取,天然防 XSS 泄露 - 小程序和 App 端无法使用 httpOnly cookie,此时 token 必须配合设备绑定、IP 限流、异常登录告警等服务端策略
- 不要把 token 存进
uni.setStorageSync后再手动拼进 header,应封装统一 request 拦截器自动注入
真要存密码凭证?必须用 AES + 设备绑定密钥
仅当业务强要求“记住密码”(如内网系统无互联网访问、无后端改接口权限),才考虑客户端加密存储。但绝不能用 Base64、md5、sha256 等可逆或单向哈希——它们不是加密,只是编码或摘要。
- 必须用 AES-CBC 或 AES-GCM,且 key 不能硬编码,需结合设备指纹动态生成(如
uni.getSystemInfoSync().model + appid) - IV 必须每次随机,不能固定;加密后结果用 Base64 编码再存入
uni.setStorageSync - 解密时需校验设备一致性(例如比对当前
model是否与加密时一致),不一致则拒绝解密 - 示例关键逻辑:
AES.encrypt(this.password, this.deriveKey(), { iv: this.randomIV() })
别忽略多端差异带来的安全盲区
同一个加密逻辑,在 H5、微信小程序、App 三端表现可能完全不同。比如:
- H5 环境可用
Web Crypto API,但微信小程序不支持;App 端若用原生模块加密,JS 层无法验证密钥是否真的安全生成 - 小程序的
uni.getStorageInfoSync()可列出所有 key,攻击者能轻易发现encrypted_psw这类命名 - Android 10+ 上,即使你用了 AES,如果密钥派生依赖了
getBatteryLevel这类不稳定字段,换手机或重装 App 后就再也解不开
最易被忽略的一点:加密本身不解决“谁在调用解密函数”的问题。没有生物识别或系统级密码确认环节,任何 JS 代码都能触发解密——包括被注入的恶意脚本。











