我试图替换一些涉及存储在字符串变量中的现有逻辑,以使用字节数组(出于安全原因)。接下来有两个块,其中方法A()具有旧逻辑,方法B()具有替换逻辑。但是,在相似点打印输出时,在字节数组的情况下,我会看到不同的输出。我想念什么吗?
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World ");
A();
B();
}
public static void A()
{
String expDetails = "";
if (true) {
String expYear = "1986";
expDetails = expYear;
}
System.out.println("Output in between "+expDetails);
// expiry month in MM
String monthStr = "";
if (true) {
String expiryMonth = "12";
int month = Integer.parseInt(expiryMonth) + 1;
expDetails += month > 9 ? String.valueOf(month) : "0" + month;
}
System.out.println("Output "+expDetails);
}
public static void B()
{
byte[] expDetailsNew = null;
if (true) {
String expYear = "1986";
expDetailsNew = expYear.getBytes();
System.out.println("Inside");
}
System.out.println("Output in between "+expDetailsNew.toString());
String monthStr = "";
if (true) {
String expiryMonth = "12";
int month = Integer.parseInt(expiryMonth) + 1;
if(month>9)
{
byte[] c = new byte[expDetailsNew.length + Integer.toString(month).length()];
System.arraycopy(expDetailsNew, 0, c, 0, expDetailsNew.length);
System.arraycopy(expDetailsNew, 0, c, expDetailsNew.length, Integer.toString(month).length());
String finalVal = new String(c);
System.out.println("Output "+finalVal);
}
}
}
}
以下是输出-
Hello World
Output in between 1986
Output 198613
Inside
Output in between [B@6d06d69c
Output 198619
更新
按照@VGR的回答,尝试附加这样的月份值-
CharBuffer another = CharBuffer.allocate(2);
new Formatter(another).format("%02d", month);
expDetailsNew.append(another);
expDetailsNew.flip();
System.out.println("Output "+expDetailsNew.toString());
但是输出为空。
答案 0 :(得分:1)
为避免将敏感信息存储在字符串中,请使用char
数组。不要使用平台的默认字符集转换为字节;您有破坏信息的风险。实际上,Java SE中许多与安全性相关的方法已经使用char
数组:
虽然您可以使用System.arraycopy
,但是CharBuffer的使用更加容易,甚至具有有用的toString方法。
您的original question显示的代码比该问题中的代码清晰得多,因此我将使用其中的代码:
CharBuffer expDetails = CharBuffer.allocate(6);
// extract expiry year in YYYY
if (!CommonUtil.isEmpty(paymentDetails.getExpiryYear())) {
expDetails.append(paymentDetails.getExpiryYear());
}
// expiry month in MM
if (!CommonUtil.isEmpty(paymentDetails.getExpiryMonth())) {
int month = Integer.parseInt(paymentDetails.getExpiryMonth()) + 1;
new Formatter(expDetails).format("%02d", month);
}
expDetails.flip();
reqParams.put("CardNum",
encrypt(params[4], paymentDetails.getCardNumber()));
reqParams.put("expiryDate", encrypt(params[4], expDetails.toString()));
reqParams.put("CVVNum",
encrypt(params[4], paymentDetails.getCvvNumber()));
正如漏洞报告所指出的那样,String对象是不可变的并且可以被嵌入,以减少冗余分配。从理论上讲,这意味着恶意代码可以访问其他对象使用的String对象。为避免这种可能性并加强字符串值的安全性,可以更改encrypt
方法以接受char[]
参数而不是字符串。例如:
public byte[] encrypt(String key, char[] sourceValue) {
Formatter hex = new Formatter(Locale.US);
for (char c : sourceValue) {
hex.format("%04x", (int) c);
}
return hex.getBytes(StandardCharsets.UTF_8);
}
(这只是一个示例,基于您的评论;我不知道您的encrypt
方法的实际作用。)
也不要写任何空白的catch
块。由于这似乎是一种Web服务方法,因此您应该只需删除try / catch即可,只需在方法的throws
子句中添加必要的例外即可。您真的不希望用户在应用程序无法正常工作时就认为它正在运行,对吗?
答案 1 :(得分:0)
System.out.println("Output in between "+new String(expDetailsNew));
上面解决了对象引用。
尝试更改
System.arraycopy(expDetailsNew, 0, c, expDetailsNew.length,
到
System.arraycopy(Integer.toString(month).getBytes(), 0, c, expDetailsNew.length,