一、前言
关于logstash的logstash-master.zip源码包中org.logstash.secret.store.SecretStoreUtil数据安全储存工具类,实现敏感数据清除出内存(客户等敏感数据不能储存在内存中),从而避免不可控的数据任意泄露,主要通过常见场景公共方法处理解决问题。
1.将二进制数据转换为字符数据,便于敏感数据识别,方法是asciiBytesToChar、asciiCharToBytes(将处理后的数据还原二进制存储)@b@2.将二进制数据进行base64加密base64Encode处理,避免敏感数据出现,再base64Decode解密输出使用@b@3.直接清除特殊场景二进制数据clearChars@b@4.字符数据随机混淆处理算法deObfuscate、obfuscate
二、源码说明
package org.logstash.secret.store;@b@@b@import java.nio.ByteBuffer;@b@import java.util.Arrays;@b@import java.util.Base64;@b@import java.util.Random;@b@@b@/**@b@ * Conversion utility between String, bytes, and chars. All methods attempt to keep sensitive data out of memory. Sensitive data should avoid using Java {@link String}'s.@b@ */@b@final public class SecretStoreUtil {@b@@b@ /**@b@ * Private constructor. Utility class.@b@ */@b@ private SecretStoreUtil() {@b@ }@b@@b@ private static final Random RANDOM = new Random();@b@@b@ /**@b@ * Converts bytes from ascii encoded text to a char[] and zero outs the original byte[]@b@ *@b@ * @param bytes the bytes from an ascii encoded text (note - no validation is done to ensure ascii encoding)@b@ * @return the corresponding char[]@b@ */@b@ public static char[] asciiBytesToChar(byte[] bytes) {@b@ char[] chars = new char[bytes.length];@b@ for (int i = 0; i < bytes.length; i++) {@b@ chars[i] = (char) bytes[i];@b@ bytes[i] = '\0';@b@ }@b@ return chars;@b@ }@b@@b@ /**@b@ * Converts characters from ascii encoded text to a byte[] and zero outs the original char[]@b@ *@b@ * @param chars the chars from an ascii encoded text (note - no validation is done to ensure ascii encoding)@b@ * @return the corresponding byte[]@b@ */@b@ public static byte[] asciiCharToBytes(char[] chars) {@b@ byte[] bytes = new byte[chars.length];@b@ for (int i = 0; i < chars.length; i++) {@b@ bytes[i] = (byte) chars[i];@b@ chars[i] = '\0';@b@ }@b@ return bytes;@b@ }@b@@b@ /**@b@ * Base64 encode the given byte[], then zero the original byte[]@b@ *@b@ * @param b the byte[] to base64 encode@b@ * @return the base64 encoded bytes@b@ */@b@ public static byte[] base64Encode(byte[] b) {@b@ byte[] bytes = Base64.getEncoder().encode(b);@b@ clearBytes(b);@b@ return bytes;@b@ }@b@@b@ /**@b@ * Base64 encode the given byte[], then zero out the original byte[]@b@ *@b@ * @param bytes the byte[] to base64 encode@b@ * @return the char[] representation of the base64 encoding@b@ */@b@ public static char[] base64EncodeToChars(byte[] bytes) {@b@ return asciiBytesToChar(base64Encode(bytes));@b@ }@b@@b@ /**@b@ * Base64 encode the given char[], then zero out the original char[]@b@ *@b@ * @param chars the char[] to base64 encode@b@ * @return the char[] representation of the base64 encoding@b@ */@b@ public static char[] base64Encode(char[] chars) {@b@ return asciiBytesToChar(base64Encode(asciiCharToBytes(chars)));@b@ }@b@@b@ /**@b@ * Decodes a Base64 encoded byte[], then zero out the original byte[]@b@ *@b@ * @param b the base64 bytes@b@ * @return the non-base64 encoded bytes@b@ */@b@ public static byte[] base64Decode(byte[] b) {@b@ byte[] bytes = Base64.getDecoder().decode(b);@b@ clearBytes(b);@b@ return bytes;@b@ }@b@@b@ /**@b@ * Decodes a Base64 encoded char[], then zero out the original char[]@b@ *@b@ * @param chars the base64 chars@b@ * @return the non-base64 encoded chars@b@ */@b@ public static byte[] base64Decode(char[] chars) {@b@ return base64Decode(asciiCharToBytes(chars));@b@ }@b@@b@ /**@b@ * Attempt to keep data out of the heap.@b@ *@b@ * @param chars the bytes to zero out@b@ */@b@ public static void clearChars(char[] chars) {@b@ Arrays.fill(chars, '\0');@b@ }@b@@b@ /**@b@ * Attempt to keep data out of the heap.@b@ *@b@ * @param bytes the bytes to zero out@b@ */@b@ public static void clearBytes(byte[] bytes) {@b@ Arrays.fill(bytes, (byte) '\0');@b@ }@b@@b@@b@ /**@b@ * De-obfuscates the obfuscated char[] generated by {@link SecretStoreUtil#obfuscate(char[])}@b@ *@b@ * @param chars The chars to de-obscure@b@ * @return the de-obscured chars@b@ */@b@ public static char[] deObfuscate(char[] chars) {@b@ byte[] bytes = asciiCharToBytes(chars);@b@ byte[] random = Arrays.copyOfRange(bytes, bytes.length / 2, bytes.length);@b@ byte[] deObfuscated = new byte[random.length];@b@ for (int i = 0; i < random.length; i++) {@b@ int xor = bytes[i] ^ random[i];@b@ deObfuscated[i] = ((byte) (xor & 0xff));@b@ }@b@ return asciiBytesToChar(deObfuscated);@b@ }@b@@b@ /**@b@ * <p>Simple obfuscation that adds a bit of randomness and shuffles the bits of a char[].</p>@b@ * <p>Note - this is NOT security and will only deter the lazy.</p>@b@ *@b@ * @param chars The chars to obscure@b@ * @return the obscured bytes@b@ */@b@ public static char[] obfuscate(char[] chars) {@b@ byte[] bytes = asciiCharToBytes(chars);@b@ byte[] random = new byte[bytes.length];@b@ RANDOM.nextBytes(random);@b@@b@ ByteBuffer obfuscated = ByteBuffer.allocate(bytes.length * 2);@b@ for (int i = 0; i < bytes.length; i++) {@b@ int xor = bytes[i] ^ random[i];@b@ obfuscated.put((byte) (0xff & xor));@b@ }@b@ obfuscated.put(random);@b@ char[] result = asciiBytesToChar(obfuscated.array());@b@ clearBytes(obfuscated.array());@b@ return result;@b@ }@b@}