【问题标题】:Malicious code vulnerability - May expose internal representation by incorporating reference to mutable object恶意代码漏洞 - 可能通过合并对可变对象的引用来暴露内部表示
【发布时间】:2013-09-28 02:11:00
【问题描述】:

我的 dto 类中有以下代码。

public void setBillDate(Date billDate) {
    this.billDate = billDate;
}

我在声纳中遇到了这样的错误,我不确定我在这里做错了什么。

Malicious code vulnerability - May expose internal representation by incorporating reference to mutable object   

该类是一个dto,该方法是自动创建的setter方法。我在这里做错了什么。如果有人能解释一下。这将是一个很大的帮助。

【问题讨论】:

  • 您可以尝试改用this.billDate = new Date(billDate.getTime());...
  • 是dto;数据传输对象?未定义的首字母缩略词只会导致混淆
  • 对不起,它不是一个 dto.. 它是一个实体类。对不起!

标签: java


【解决方案1】:

Date 是可变的

使用该设置器,某人可以从外部无意中修改日期实例

考虑一下

class MyClass {

   private Date billDate;


   public void setBillDate(Date billDate) {
      this.billDate = billDate;
   }

}

现在有人可以设置它

MyClass m = new MyClass();

Date dateToBeSet = new Date();
m.setBillDate(dateToBeSet); //The actual dateToBeSet is set to m

dateToBeSet.setYear(...); 
//^^^^^^^^ Un-intentional modification to dateToBeSet, will also modify the m's billDate 

为避免这种情况,您可能需要在设置之前深复制

public void setBillDate(Date billDate) {
    this.billDate = new Date(billDate.getTime());
}

【讨论】:

  • 如果我的实例变量是日期数组,如何实现?我可以使用 Arrays.copyOf 吗?
  • @yathirigan 是的。基本上你需要做深拷贝,这样外部修改不会影响这个实例中保存的对象
  • 谢谢.. 看到几篇声明 Arrays.copyOf 不进行深度复制的文章,我感到很困惑。我正在阅读它。
  • 克隆也很有用,例如。 billDate.clone()
  • 如果我们写 this.billDate = billDate.clone(); 会怎样?也是一样的
【解决方案2】:

我想知道为什么没有一个解决方案将 null 考虑在内。一个通用的、null 安全的解决方案应该如下所示:

public void setBillDate(Date billDate) {
    this.billDate = billDate != null ? new Date(billDate.getTime()) : null;
}

【讨论】:

  • 也许是因为你应该避免使用空值,因为它被许多人认为是反模式
  • @Zavael 重点是“你不知道课外的人会如何处理这些价值观”。你不能指望每个人都不会给你一个空值。
  • @Demonblack 我同意你不能期望每个人都永远不传递空值,但你可以用适当的例外来“惩罚”他们 :) 如果调用者没有要设置的值,他应该'根本不调用方法
  • @Zavael 或者,我们可以接受 Date 为空,而不是仅仅惩罚他们。就像这个答案一样。
  • @Zavael 大多数时候抛出异常是一个不错的选择。但最近我正在处理 JPA,在 get/set 函数中有一个可为空的 Date 字段。我需要考虑 null 情况,因为设置/获取 null Date 是合法的。
【解决方案3】:

Date 是可变的

而你没有创建一个 的副本 Date 传入你的是参数。所以如果客户端代码会改变Date对象的值,它也会影响你的类。

解决方案是创建Date的副本

public setBillDate(Date billDate){
   this.billDate = new Date(billDate.getTime());
}

【讨论】:

    【解决方案4】:

    也可以考虑使用克隆。不要忘记空检查。

    public void setBillDate(Date billDate) {
        this.billDate = billDate == null ? null : billDate.clone();
    }
    

    【讨论】:

    • 这可能是 java.util.Date 的一个选项(对于 Java 7+,请参阅 stackoverflow.com/a/18954948/1098673 上的 cmets),请参阅:stackoverflow.com/a/7082614/1098673 但通常它不是正确的解决方案,请参阅:@ 987654323@
    • billDate.clone() 返回一个对象,您必须将其强制转换(我认为这很糟糕)为日期对象才能设置字段。
    【解决方案5】:

    除了现有的答案之外,我还提出了一个基于 Java 8 的 Optional 类的新版本。

    public void setBillDate(Date billDate) {
        this.billDate = Optional
                .ofNullable(billDate)
                .map(Date::getTime)
                .map(Date::new)
                .orElse(null);
    }
    

    【讨论】:

      【解决方案6】:

      一个反驳的论点可以是,为什么一个人会无意修改日期?如果客户端设置了值然后修改它,那么我们的代码应该反映它,不是吗?如果不是,那不是很混乱吗?

      我宁愿忽略这个 FindBugs 警告。

      如果您想这样做,只需在您的 pom.xml 中添加以下 Maven 依赖项:

      <!-- Findbugs -->
              <dependency>
                  <groupId>com.google.code.findbugs</groupId>
                  <artifactId>annotations</artifactId>
                  <version>3.0.1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>com.google.code.findbugs</groupId>
                  <artifactId>annotations</artifactId>
                  <version>3.0.1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>com.google.code.findbugs</groupId>
                  <artifactId>jsr305</artifactId>
                  <version>3.0.1</version>
                  <scope>provided</scope>
              </dependency>
      

      然后是 POJO 中类或成员字段级别的这些注释:

      @SuppressFBWarnings(value = { "EI_EXPOSE_REP", "EI_EXPOSE_REP2" }, justification = "I prefer to suppress these FindBugs warnings")
      

      干杯

      阿克谢

      【讨论】:

        【解决方案7】:

        日期不是一成不变的,即你的 billDate 可以在你的 DTO 对象上设置后更改。或者,在代码中:

        Date billDate = new Date();
        dto.setBillDate(billDate);
        billDate.setYear(1990);
        // now, dto.getBillDate().getYear() == 1990
        

        你可以让你的 setter 更安全:

        public void setBillDate(Date billDate) {
            this.billDate = (Date)billDate.clone();
        }
        

        【讨论】:

        • 默认clone()会创建浅拷贝,所以可能无法解决问题
        • 在 Oracle 的 JDK 7 中,它被覆盖以创建深层副本。但你是对的,API 文档只说:“返回此对象的副本。” - 这并没有完全解释它创建的副本类型。
        【解决方案8】:

        37 号最佳答案不是正确答案:没人关心 NullPointerExceptions???

        你应该试试这个:

        public void setBillDate(Date billDate) {
            this.billDate = billDate == null ? billDate : new Date(billDate.getTime());
        }
        

        【讨论】:

        猜你喜欢
        • 2012-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-04
        • 1970-01-01
        相关资源
        最近更新 更多