Java 相当于 SecureString

2022-09-01 17:30:57

我正在寻找Java的等效物。NET的SecureString.aspx。2018年是否有这样的实施?

OWASP 实现并不完全相同,因为它只是一个普通的 char 数组。而 .NET 等效项提供了其他功能,例如从/到非托管内存获取实例的功能以及加密。

我知道常见的Java模式可以传递密码,并在使用后用零来做。但它需要一直构建一个微不足道的实用程序类。char[]Arrays.fill()char[]


答案 1

Oracle有一个GuardedString实现。它是最接近的匹配项。NET 的 SecureString 解决方案。

安全字符串实现,解决了与将密码保存为 相关的问题。也就是说,表示为 String 的任何内容都作为明文密码保存在内存中,并至少在垃圾回收之前保留在内存中。java.lang.String

该类通过将字符以加密形式存储在内存中来缓解此问题。加密密钥将是随机生成的密钥。GuardedString

在其序列化形式中,将使用已知的默认密钥对 s 进行加密。这是为了提供最低级别的保护,而不管传输方式如何。对于与远程连接器框架的通信,建议部署启用 SSL 以实现真正的加密。GuardedString

应用程序可能还希望持久化 。对于标识管理器,它应该将 s 转换为,以便可以使用标识管理器的“管理加密”功能来存储和管理它们。其他应用程序可能希望作为一个整体进行序列化。这些应用程序负责加密 Blob 以获得额外的安全层(超出 提供的基本默认密钥加密)。GuardedStringGuardedStringEncryptedDataAPIConfigurationAPIConfigurationGuardedString


答案 2

我修改了OWASP版本以随机填充内存中的char数组,因此静态的char数组不会与实际字符一起存储。

import java.security.SecureRandom;
import java.util.Arrays;


/**
* This is not a string but a CharSequence that can be cleared of its memory.
* Important for handling passwords. Represents text that should be kept
* confidential, such as by deleting it from computer memory when no longer
* needed or garbaged collected.
*/
public class SecureString implements CharSequence {

   private final int[] chars;
   private final int[] pad;

   public SecureString(final CharSequence original) {
      this(0, original.length(), original);
   }

   public SecureString(final int start, final int end, final CharSequence original) {
      final int length = end - start;
      pad = new int[length];
      chars = new int[length];
      scramble(start, length, original);
   }

   @Override
   public char charAt(final int i) {
      return (char) (pad[i] ^ chars[i]);
   }

   @Override
   public int length() {
      return chars.length;
   }

   @Override
   public CharSequence subSequence(final int start, final int end) {
      return new SecureString(start, end, this);
   }

   /**
    * Convert array back to String but not using toString(). See toString() docs
    * below.
    */
   public String asString() {
      final char[] value = new char[chars.length];
      for (int i = 0; i < value.length; i++) {
         value[i] = charAt(i);
      }
      return new String(value);
   }

   /**
    * Manually clear the underlying array holding the characters
    */
   public void clear() {
      Arrays.fill(chars, '0');
      Arrays.fill(pad, 0);
   }

   /**
    * Protect against using this class in log statements.
    * <p>
    * {@inheritDoc}
    */
   @Override
   public String toString() {
      return "Secure:XXXXX";
   }

   /**
    * Called by garbage collector.
    * <p>
    * {@inheritDoc}
    */
   @Override
   public void finalize() throws Throwable {
      clear();
      super.finalize();
   }

   /**
    * Randomly pad the characters to not store the real character in memory.
    *
    * @param start start of the {@code CharSequence}
    * @param length length of the {@code CharSequence}
    * @param characters the {@code CharSequence} to scramble
    */
   private void scramble(final int start, final int length, final CharSequence characters) {
      final SecureRandom random = new SecureRandom();
      for (int i = start; i < length; i++) {
         final char charAt = characters.charAt(i);
         pad[i] = random.nextInt();
         chars[i] = pad[i] ^ charAt;
      }
   }

}