为了账号安全,请及时绑定邮箱和手机立即绑定

字节数组在替换字符串变量时给出不同的输出

字节数组在替换字符串变量时给出不同的输出

繁星淼淼 2023-03-17 14:02:09
我正在尝试替换一些现有的涉及字符串变量存储的逻辑,以使用字节数组(出于安全原因)。下面有两个块方法 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 1986Output 198613InsideOutput in between [B@6d06d69cOutput 198619更新根据@VGR 的回答,尝试像这样附加月份值 -CharBuffer another = CharBuffer.allocate(2); new Formatter(another).format("%02d", month); expDetailsNew.append(another);expDetailsNew.flip();System.out.println("Output "+expDetailsNew.toString());但是输出是空的。
查看完整描述

2 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

为避免在字符串中存储敏感信息,请使用char数组。不要使用平台的默认字符集转换为字节;您冒着破坏信息的风险。事实上,Java SE 中许多与安全相关的方法已经使用了char数组:

虽然您可以使用System.arraycopy,但使用CharBuffer更容易,它甚至有一个有用的toString方法。

最初的问题显示的代码比这个问题中的代码清晰得多,因此我将使用其中的代码:

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子句中。你真的不希望用户认为应用程序在实际工作时没有工作,对吧?


查看完整回答
反对 回复 2023-03-17
?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

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,


查看完整回答
反对 回复 2023-03-17
  • 2 回答
  • 0 关注
  • 92 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信