在学习Java时,我了解到Strings 对于存储密码是不安全的,因为你无法手动清除与它们相关的内存(你不能确定它们最终会被gc'ed,内部字符串可能永远不会,甚至之后gc你不能确定物理内存内容真的被擦除了).相反,我使用char数组,所以我可以在使用后将它们清零.我试图在其他语言和平台上搜索类似的做法,但到目前为止我找不到相关的信息(通常我看到的是密码存储在字符串中的代码示例,没有提到任何安全问题).
我对浏览器的情况特别感兴趣.我经常使用jQuery,而我通常的做法就是将密码字段的值设置为空字符串而忘记它:
$(myPasswordField).val("");
Run Code Online (Sandbox Code Playgroud)
但我并不是100%确信它已经足够了.我也不知道用于中间访问的字符串是否安全(例如,当我$.ajax用来将密码发送到服务器时).至于其他语言,通常我没有提到这个问题(我特别感兴趣的另一种语言是Python).
我知道试图建立列表的问题是有争议的,但由于这涉及一个很大程度上被忽视的共同安全问题,恕我直言,这是值得的.如果我弄错了,我会很高兴知道从JavaScript(在浏览器中)和Python.我也不确定是在这里,在security.SE还是在程序员.SE,但由于它涉及安全执行任务的实际代码(不是概念性问题),我相信这个网站是最好的选择.
注意:在低级语言或明确支持字符作为原始类型的语言中,答案应该是显而易见的(编辑:不是很明显,正如@Gabe在下面的答案中所示).我要求那些"一切都是对象"或类似的高级语言,以及那些在幕后执行自动字符串实习的人(所以你可能会创建一个安全漏洞而不会意识到它,即使你'合理谨慎).
更新:根据相关问题的答案,即使char[]在Java中使用也不能保证是防弹的(或者就此而言是.NET SecureString),因为gc可能会移动数组,因此其内容可能会粘在内存中,即使在清除(SecureString至少保留在相同的RAM地址中,保证清除,但其消费者/生产者可能仍然留下痕迹).
我猜@NiklasB.是正确的,即使漏洞存在,漏洞利用的可能性很低,防止漏洞的难度很高,这可能是这个问题大多被忽视的原因.我希望我至少可以找到关于浏览器这个问题的一些参考,但谷歌搜索到目前为止一直没有结果(这个场景至少有一个名字吗?).
我JPasswordField在我的程序中使用了一个.当我问getPassword(),我得到一个char[]数组.但是,当我添加ActionListener的JPasswordField,问getActionCommand(),我得到的密码作为String.此密码是否在事件对象中保存为String?这不是一个安全问题吗?
我阅读了几篇关于安全性的文章和帖子(注意 在Web应用程序中将输入密码与存储的哈希密码进行比较,或者为什么char []首选字符串用于密码?
由于从请求中检索参数值使用返回String的request.getParameter("passwordFieldName"),是否有任何选项可以从请求中检索参数作为char []?
正如标题所说,我正在寻找一种方法来使用char []数组来建立JDBC连接,而不是从char []数组创建一个新的String对象,并使用它来建立连接.
因为char []数组比java中的字符串更安全,所以我一直希望在处理我的JPasswordField时尽可能保证安全.
在这种特殊情况下,我将获取JPasswordField的char []数组内容并尝试建立与数据库的JDBC连接.它运行得很好,但是我必须从char []数组创建一个新的String对象来实际调用getConnection方法.
有没有办法确保至少有一些安全性这样做,或者我只是被迫创建String对象并继续在方法中使用它?
这是我的代码:
/**
* Construct a new DataManager object with it's own
* connection to the database.
*
* @param ipAddress The IP address to the server on which MySQL is running.
* @param port The port to use when connecting to MySQL.
* @param databaseName The database name of the database to connect to.
* @param username The username for a MySQL account with access to the …Run Code Online (Sandbox Code Playgroud) 这是一个内存数据安全性问题。
Java垃圾收集是否可以安全清除垃圾数据?
显然,在大块数据被垃圾回收之后,我再也无法检索它了,但是黑客仍然可以通过内存转储来检索数据吗?
在Java中,建议char[]用于存储密码或其他敏感信息,以便在不再需要数据时能够手动清除它。
如何在所有线程中清除这样的数组?如果我理解正确,线程可能只会在其缓存中执行更改,而不会在共享内存中执行更改,因此以下操作将无法可靠地运行:
char[] password = ...
...
Arrays.fill(password, '\0');
Run Code Online (Sandbox Code Playgroud)
volatile(或其他同步方式)确保共享内存已更新?
编辑:char[]应该用于密码的语句是基于为什么为什么char []优于String?但是,再次查看之后,这也引起了一些争议。
我是一名软件工程师,正在构建一个将由政府机构使用的 Android 应用程序。
我们合同中的一项要求是应用程序必须符合 FIPS 140。 https://en.wikipedia.org/wiki/FIPS_140
为了符合 FIPS,我们的应用程序必须在 android 应用程序关闭时将 RAM 中的所有密码对象归零并清除。(通过从 RAM 中清零和清除密码,我们减少了攻击者的机会窗口。即这减轻了冷启动攻击风险:https : //en.wikipedia.org/wiki/Cold_boot_attack)
为了满足这一要求,我们最初遵循以下两个 SO 帖子中的建议将用户密码捕获为 CharArray 而不是字符串
//First collect the password from Edit Text as a []char
int pl = passwordEditText.length();
char[] password = new char[pl];
passwordEditText.getText().getChars(0, pl, password, 0);
//Now set the password on viewmodel
viewModel.setPassword(password)
Run Code Online (Sandbox Code Playgroud)
获得密码后,我们使用它来调用第 3 方网络服务库,该库获取数据以显示在屏幕上。
视图模型伪代码:
public DataObject getData(char[] password){
return this.webService.getData(password);
}
Run Code Online (Sandbox Code Playgroud)
当用户完成我们的应用程序时,我们调用以下方法将密码归零和清除
视图模型伪代码:
public zeroPassword(){
Arrays.fill(this.password, 0);
this.password = null; …Run Code Online (Sandbox Code Playgroud) java.io.Console类的javadoc中有一个安全说明:
安全说明:如果应用程序需要读取密码或其他安全数据,则应使用readPassword()或readPassword(String,Object ...)并在处理后手动将返回的字符数组归零,以最大限度地缩短内存中敏感数据的生命周期.
Console cons;
char[] passwd;
if ((cons = System.console()) != null &&
(passwd = cons.readPassword("[%s]", "Password:")) != null) {
...
java.util.Arrays.fill(passwd, ' ');
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么你需要这么激烈的措施?当读取密码的方法弹出堆栈时,passwd局部变量引用的数组对象将有资格进行垃圾回收.没有人(甚至是攻击者)可以获得对该数组的引用,假设数组没有转义方法范围.
那么为什么你需要修改数组(删除密码),当你知道一旦方法弹出堆栈就有资格获得GC?他们说:
最小化内存中敏感数据的生命周期
但对我来说,这种编程风格似乎相当......绝望.
这是我使用 JDBC 连接的登录表单的代码,代码没有错误,但是当我运行它时,它总是转到 else 语句
Connection con;
Statement st;
ResultSet rs;
try{
Class.forName("java.sql.Driver");
con=DriverManager.getConnection ("jdbc:mysql://localhost/database","root","password");
st=con.createStatement();
rs=st.executeQuery("select * from users;");
while(rs.next()){
String userID=rs.getString("userID");
String password=rs.getString("password");
if(userID.equals(txtuserID.getText())
&& (password.equals(txtpassword.getPassword())) {
// ***HERE IS MY PROBLEM I WANT TO CHECK IF WHATS IN THE
// TEXT FIELD OR PASSWORD FIELD IS THE SAME FROM MySQL***
JOptionPane.showMessageDialog(null,"you have logged in");
new MainForm().setVisible(true);
} else {
JOptionPane.showMessageDialog(null,"Incorrect username and password");
}
}
} catch(Exception e) {
JOptionPane.showMessageDialog(null,"Error in Connectivity: " +e.getMessage());
}
Run Code Online (Sandbox Code Playgroud) 我正在开发一个 Java 服务,该服务记录了一个安全错误,涉及存储在 Java String 对象中的秘密。
令人担忧的是,一旦密码存储在 a 中String,它就会保留在字符串池中,直到被垃圾收集,并且可能会以明文形式显示在转储中。
我理解Java的String类是不可变的,最好将秘密或密码存储在可变的类中,这样在使用后可以尽快从内存中删除。
参考
然而,我发现在使用第三方库时这是不切实际的,因为他们中的许多人都希望将请求中的密码或秘密作为 String 对象传递,无论我多么安全,在我的代码中,最终都会将数组转换char[]为String,这让我们回到了最初的问题,不是吗?
那么,是否有办法将 achar[]或转换StringBuffer为 a String,而不回到原来的问题?
编辑:正如这个问题和其他类似问题中的评论所指出的,许多人认为这不是真正的问题,因为如果您不拥有应用程序中的所有代码(即不拥有),则没有简单的方法可以避免此问题不要将秘密传递给任何第三方库)。鉴于此,也许问题就变成了
我该如何反驳该错误?Oracle/Owasp 或任何说“无法解决的问题”的人是否有可靠的参考资料?