- 如果运行 UI 的用户知道密码,那么我并没有真正看到您的安全问题。你在为谁辩护?
- 如果运行 UI 的用户不知道密码(并且密码应该存储在测试用例本身中),那么你就陷入困境 - 加密很好,但你必须存储密码以某种方式解密......无尽的循环,没有安全的空间。即使存储是安全的,弱点肯定是传输到浏览器(无论如何都将作为封装在 JSON 中的纯字符串完成)和自动输入到浏览器本身。说真的,如果您不信任运行测试的机器,请不要存储密码。
但是,对于第一种情况(当用户必须在 UI 中输入密码时),为了最大限度地减少威胁的可能性并为了最大的方便,我会这样做:
- 创建一个单例类
PasswordHolder
- a
PasswordHolder
会记住 a 中的密码(由 给他们JPasswordField
)Map<String, char[]>
或Map<String, Password>
其中 key 是某个密码标识符,而 value 是密码本身
- 一旦通过
getPassword()
方法访问密码,其内容将被取消
一个快速的示例实现(为了进一步改进,我希望我不会忘记包含任何重要的东西......但它可能会发生)。我认为它有点不言自明:
public class PasswordHolder {
private static PasswordHolder instance = null;
private final Map<String, Password> map = new HashMap<String, Password>();
private PasswordHolder() {
// nothing to do
}
public static PasswordHolder getInstance() {
if (instance == null) {
instance = new PasswordHolder();
}
return instance;
}
public void addPassword(String name, char[] pass) {
if (map.containsKey(name)) {
// throw some sort of Exception("Duplicate password name, man.")
}
map.put(name, new Password(pass));
}
public Password getPassword(String name) {
return map.get(name);
}
}
作为最方便的事情,我写Password
了一个CharSequence
所以是有用的sendKeys(CharSequence keys)
。不幸的是,sendKeys()
使用toString()
了,所以无论如何你都必须从密码中创建一个字符串(这被认为是一种不好的做法)。
public class Password implements CharSequence {
private final char[] pass;
private final BitSet nulled;
Password(char[] pass) {
this.pass = pass;
nulled = new BitSet(pass.length);
}
private void nullify(int start, int end) {
for (int i = start; i < end; i++) {
pass[i] = '\0';
}
nulled.set(start, end);
}
@Override
public int length() {
return pass.length;
}
@Override
public char charAt(int index) {
if (nulled.get(index)) {
// throw some Exception("That character has already been read!")
}
char ret = pass[index];
pass[index] = '\0';
nulled.set(index);
return ret;
}
@Override
public CharSequence subSequence(int start, int end) {
if (nulled.get(start, end).cardinality() > 0) {
// throw some Exception("Some of the characters has already been read!")
}
Password subPass = new Password(Arrays.copyOfRange(pass, start, end));
nullify(start, end);
return subPass;
}
@Override
public String toString() {
if (nulled.cardinality() > 0) {
// throw some Exception("Some of the characters has already been read!")
}
String str = new String(pass);
nullify(0, pass.length);
return str;
}
}