在垃圾收集之前,通过使用反射来清理内容,安全地使用String来获取密码 [英] Safely using String for passwords by using reflection to scrub contents prior to garbage collection

查看:139
本文介绍了在垃圾收集之前,通过使用反射来清理内容,安全地使用String来获取密码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用反射来清理 String make使用 String 与使用 char一样安全[] 用于密码?



从安全角度来看,通常认为使用 char [] 用于存储/传递密码,因为可以尽快在代码中清零它的内容,这可能在垃圾回收清理它之前显着并且内存被重用(擦除所有跟踪),限制但是, char [] 不如<$ c $方便c> String ,所以如果需要的话可以清理一个 String ,这会很方便,从而使得 String char []



一样安全。下面是一个使用反射为零的方法 - 字符串



这个方法是OK,并且它是否达到了制作目标字符串 char [] 一样安全吗?

  public static void scrub(String str)throws NoSuchFieldException,IllegalAccessException {
Field valueField = String.class.getDeclaredField(value);
字段offsetField = String.class.getDeclaredField(offset);
Field countField = String.class.getDeclaredField(count);
Field hashField = String.class.getDeclaredField(hash);
valueField.setAccessible(true);
offsetField.setAccessible(true);
countField.setAccessible(true);
hashField.setAccessible(true);
char [] value =(char [])valueField.get(str);
//用空字符覆盖相关的数组内容
Arrays.fill(value,offsetField.getInt(str),countField.getInt(str),'\0');
countField.set(str,0); //擦洗密码长度也是
hashField.set(str,0); //散列可以用来破解密码
valueField.setAccessible(false);
offsetField.setAccessible(false);
countField.setAccessible(false);
hashField.setAccessible(false);
}

以下是一个简单的测试:

  String str =password; 
scrub(str);
System.out.println('''+ str +'');

输出:

 

注意:不是 String 常量,因此调用此方法将不会对实际的字符串产生不利影响。



另外,为简单起见,该方法是相当原始的状态。如果我要使用它,我不会声明抛出的异常(try / catch /忽略它们)并重构重复的代码。

解决方案

有两个潜在的安全问题:


  1. 字符串可能与其他字符串共享其后备数组;例如如果 String 是通过调用 substring 在更大的 String 。因此,当您将整个数组置零时,您可以覆盖其他字符串的状态......不包含密码。



    解决方法是只清零由密码字符串使用的支持数组的部分。


  2. JLS( 17.5.3 )警告使用反射改变 final 变量的效果是未定义的。然而,上下文是Java内存模型,并且允许编译器主动缓存 final 变量。在这种情况下:


    • 你会期望String被线程限制,并且


    • 您不应该再次使用这些变量中的任何一个。



我不希望其中的任何一个是真正的问题......模块化修改值的过度激活归零






但真正的担忧是 Velociraptors 。 : - )




我很困惑,你真的会打扰这样的zap密码。当你考虑它时,你所保护的是有人可以读取进程内存......或核心转储或交换文件......以检索密码。但是如果有人可以这样做,那么你的系统安全性必须已经被破坏......因此,这些事情很可能需要 root 访问权限(或同等权限)。如果他们有 root 访问权限,他们可以调试你的程序并在你的应用程序跳过它们之前捕获密码


Does using reflection to scrub a String make using String as safe as using char[] for passwords?

From a security aspect, it is generally considered best practice to use char[] for storing/passing passwords, because one can zero-out its contents as soon as possible in code, which may be significantly before garbage collection cleans it up and the memory is reused (wiping all trace), limiting the window of time for a memory attack.

However, char[] is not as convenient as String, so it would be handy if one could "scrub" a String if needed, thus making String as safe as char[].

Below is a method that uses reflection to zero-out the fields of String.

Is this method "OK", and does it achieve the goal of making String as safe as char[] for passwords?

public static void scrub(String str) throws NoSuchFieldException, IllegalAccessException {
    Field valueField = String.class.getDeclaredField("value");
    Field offsetField = String.class.getDeclaredField("offset");
    Field countField = String.class.getDeclaredField("count");
    Field hashField = String.class.getDeclaredField("hash");
    valueField.setAccessible(true);
    offsetField.setAccessible(true);
    countField.setAccessible(true);
    hashField.setAccessible(true);
    char[] value = (char[]) valueField.get(str);
    // overwrite the relevant array contents with null chars
    Arrays.fill(value, offsetField.getInt(str), countField.getInt(str), '\0');
    countField.set(str, 0); // scrub password length too
    hashField.set(str, 0); // the hash could be used to crack a password
    valueField.setAccessible(false);
    offsetField.setAccessible(false);
    countField.setAccessible(false);
    hashField.setAccessible(false);
}

Here's a simple test:

String str = "password";
scrub(str);
System.out.println('"' + str + '"');

Output:

""

Note: You may assume that passwords are not String constants and thus calling this method will have no adverse effect on interned Strings.

Also, I have left the method is a fairly "raw" state for simplicity's sake. If I were to use it, I would not declare exceptions thrown (try/catch/ignoring them) and refactor repeated code.

解决方案

There are two potential safety concerns:

  1. The String may share its backing array with other Strings; e.g. if the String was created by calling substring on a larger String. So when you zero the entire value array you could be overwriting the state of other strings ... that don't contain passwords.

    The cure is to only zero the part of the backing array that is used by the password string.

  2. The JLS (17.5.3) warns that the effects of using reflection to change final variables is undefined.

    However, the context for this is the Java Memory Model, and the fact that the compiler is allowed to aggressively cache final variables. In this case:

    • you would expect the String to be thread-confined, and

    • you shouldn't be using any of those variables again.

I wouldn't expect either of these to be real problems ... modulo fixing the over-aggressive zeroing of value.


But the real concern is Velociraptors. :-)


I'm puzzled that you would actually bothering to zap passwords like this. When you think about it, what you are protecting against is the possibility that someone can read process memory ... or a core dump or swap file ... to retrieve passwords. But if someone can do that, your system security has to have already been compromised ... cos' those things most likely require root access (or equivalent). And if they have root access they can "debug" your program and catch the passwords before your application zaps them.

这篇关于在垃圾收集之前,通过使用反射来清理内容,安全地使用String来获取密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆