我曾经看过道格拉斯·克罗克福德的演讲,在javascript的背景下,他提到将秘密存储在封闭中可能很有用。
我想这可以像Java一样天真地实现:
select from V
我想知道:这样做有什么好处吗?它可能在某种程度上不那么安全吗?
答案 0 :(得分:3)
没理由这样做。将密码存储在字符数组中,因为如果要将它们打印出来,必须将它们显式转换为String。
考虑以下示例:
String stringPassword = "password";
char[] charactersPassword = new char[]{'p','a','s','s','w','o', 'r', 'd'};
System.out.println("Password: " + stringPassword); // Password: password
System.out.println("Password: " + charactersPassword); // Password: [C@6ce253f1
主要思想是你可以清除数组的项目,因为它不是不可变的(@Klitos Kyriacou
)。
Arrays.fill(charactersPassword, '0');
此外,如果您将密码存储为纯文本 - 字符串,它是不可变的,它将在内存中可用很长时间(仍然以某种方式可访问),直到垃圾收集器处理它。
无论如何,强烈建议我们管理一些安全库,它可以处理的不仅仅是创造一种新的(通常仍然存在风险)方式。
答案 1 :(得分:0)
这是一个非常“工程化”的例子,所以不要在你的代码中使用。
我认为使用谓词而非供应商可以更好地证明效果。
假设您按如下方式实施密码检查:
public class PasswordChecker {
private final String secretPassword;
public PasswordChecker(String secretPassword) {
this.secretPassword = secretPassword;
}
public boolean test(String password) {
return Objects.equals(this.secretPassword, password);
}
}
然后你可以创建一个传递它的实例:
final PasswordChecker passwordChecker = new PasswordChecker("changeit");
在其他地方你可以用它来检查密码:
assertThat(passwordChecker.test("foobar")).isFalse();
但对于手头有PasswordChecker
实例的客户端,用一些反射提取密码并不困难:
Field secretPasswordField = passwordChecker.getClass().getDeclaredField("secretPassword");
secretPasswordField.setAccessible(true);
String secretPassword = (String) secretPasswordField.get(passwordChecker);
System.out.print(secretPassword);
现在这里的闭包是一样的:
final String secretPassword = "changeit";
final Predicate<String> passwordChecker = password -> Objects.equals(secretPassword, password);
现在您无法从secretPassword
中提取passwordChecker
。