Java AES硬编码密钥是否为不良实践及java.util.prefs存加密凭据可行性咨询
问题解答
1. 硬编码AES密钥是否属于不良实践
是,这属于非常典型的不安全实践。只要攻击者拿到你编译后的jar包,通过简单的反编译就能直接提取到硬编码的密钥,此时你的加密防护完全失效,和直接存明文凭证没有本质区别。
另外你当前的AES实现本身也存在两个明显问题:
- 你使用
Cipher.getInstance("AES")获取实例,不同JDK的默认参数可能不同,默认一般是AES/ECB/PKCS5Padding,ECB模式是不安全的加密模式,相同的明文加密后会得到相同的密文,容易被破解。 - 加密后的字节直接强转为char拼接成字符串存储,加密后的字节包含大量不可打印字符,这种转换会出现编码丢失、乱码问题,大概率会导致后续解密失败,正确的做法是把加密后的字节数组转成Base64编码的字符串存储。
2. 可行的密钥存储方案(满足应用启动自动解密需求)
- 外部配置文件存储:将密钥放在jar包外的独立配置文件中,打包时不把配置文件打进应用包,部署时放到指定的受保护目录,给这个文件设置仅当前系统用户可读的权限,代码启动时从外部路径读取密钥,同时要把这个配置文件加入代码仓库的忽略列表,避免被提交到公共仓库。
- 调用系统原生凭证存储:Windows系统用凭据管理器、MacOS用钥匙串、Linux用GNOME Keyring/KDE Wallet,这些系统级的凭证存储本身做了完善的权限隔离,比你自己实现存储逻辑安全很多,Java可以通过第三方工具库调用这些系统接口。
- 用户输入密码衍生密钥:如果允许应用启动时用户手动输入一次密码,可以用PBKDF2、bcrypt等密钥衍生算法,将用户输入的密码加盐后衍生出AES密钥,密钥仅存在运行时内存中不落地存储,重启应用时重新输入密码生成即可。
3. 关于java.util.prefs和非对称加密的疑问
- 你完全可以用
java.util.prefs存储加密后的凭证,这个API是Java原生的跨平台偏好配置存储能力,比你自己写txt文件存储要规范很多,它在不同系统下的存储位置(Windows存在注册表、Linux/Mac存在用户目录的隐藏配置路径)本身有基础的权限隔离,只要你存的是加密后的密文,安全性是符合你的需求的。 - 不建议你用非对称加密实现这个场景,首先你的需求是本地存储加密解密,非对称加密性能远低于对称加密,完全没必要;其次你提到的“将私钥设置为用户需要记忆的密码”属于概念混淆,非对称加密的私钥是长串的随机字节,不可能让用户直接记忆,如果你想要用户输入密码解锁,直接用前面提到的“用户密码衍生对称密钥”的方案即可,效率和安全性都更高。
内容的提问来源于stack exchange,提问作者Hydrochaeris
相关产品推荐
相关产品推荐

