《Java编码指南:编写安全可靠程序的75条建议》—— 指南10:不要使用clone()方法来复制不可信的方法参数...

    xiaoxiao2024-06-02  104

    本节书摘来异步社区《Java编码指南:编写安全可靠程序的75条建议》一书中的第1章,第1.10节,作者:【美】Fred Long(弗雷德•朗), Dhruv Mohindra(德鲁•莫欣达), Robert C.Seacord(罗伯特 C.西科德), Dean F.Sutherland(迪恩 F.萨瑟兰), David Svoboda(大卫•斯沃博达),更多章节内容可以访问云栖社区“异步社区”公众号查看。

    指南10:不要使用clone()方法来复制不可信的方法参数

    创建可变方法参数的防御性副本,可以减轻来自各种安全漏洞的威胁,更多信息请参考《The CERT® Oracle® Secure Coding Standard for Java™》[Long 2012]的“OBJ06-J. Defensively copy mutable inputs and mutable internal components”。然而,对clone()方法不当地使用,可以使攻击者利用这一漏洞,提供看上去正常的参数,但随后返回意想不到的结果。这样的对象可能因此绕过验证和安全检查。当这样一个类可能会作为一个参数传递给一个方法时,应当把这个参数视为不可信任的,同时不要使用该类提供的clone()方法。另外,不要使用未经final修饰的类的clone()方法来创建防御性副本。

    该指南是指南15的一个特定实例。

    违规代码示例

    下面的违规代码示例定义了一个validateValue()方法来验证时间值。

    private Boolean validateValue(long time) {  // Perform validation  return true; // If the time is valid } private void storeDateInDB(java.util.Date date)   throws SQLException {  final java.util.Date copy = (java.util.Date)date.clone();  if (validateValue(copy.getTime())) {   Connection con =    DriverManager.getConnection(     "jdbc:microsoft:sqlserver://<HOST>:1433",     "<UID>", "<PWD>"    );   PreparedStatement pstmt =     con.prepareStatement("UPDATE ACCESSDB SET TIME = ?");   pstmt.setLong(1, copy.getTime());   // ...  } }``` storeDateInDB()方法接受一个不可信的日期参数,尝试利用其clone()方法创建一个防御性副本。这就允许攻击者通过一个继承自Date的恶意日期类来取得程序的控制权。如果攻击者的代码运行特权和storeDateInDB()方法一样,那么他只需在clone()方法里嵌入恶意代码:

    class MaliciousDate extends java.util.Date { @Override public MaliciousDate clone() {  // malicious code goes here }}`然而,如果攻击者只能提供恶意的日期参数,但是没有足够特权,他还是可以绕过验证,从而混淆程序的其余部分。试想一下这个例子:

    public class MaliciousDate extends java.util.Date {  private static int count = 0;  @Override  public long getTime() {   java.util.Date d = new java.util.Date();   return (count++ == 1) ? d.getTime() : d.getTime() - 1000;  } }``` getTime()方法第一次被调用时,这个恶意的日期看上去是一个正常的日期对象,这使得它绕过了storeDateInDB()里的验证方法。然而,实际存储在数据库中的时间却是不正确的。 ####合规解决方案 下面的合规解决方案避免了clone()方法的使用。取而代之,创建了一个新的java.util.Date对象,并在后续的代码中,使用该对象做访问控制检查和数据库插入。

    private void storeDateInDB(java.util.Date date)  throws SQLException { final java.util.Date copy = new java.util.Date(date.getTime()); if (validateValue(copy.getTime())) {  Connection con =   DriverManager.getConnection(    "jdbc:microsoft:sqlserver://:1433",    "", ""   );  PreparedStatement pstmt =   con.prepareStatement("UPDATE ACCESSDB SET TIME = ?");  pstmt.setLong(1, copy.getTime());  // ... }}`

    违规代码示例(CVE-2012-0507)

    下面的违规代码示例展示了一个Java核心类AtomicReferenceArray的构造函数,它来自于Java 1.7.0版本的第2次更新。

    public AtomicReferenceArray(E[] array) {  // Visibility guaranteed by final field guarantees  this.array = array.clone(); }``` 这段代码的调用导致漏洞被利用,在2012年4月影响了600 000台Macintosh电脑。1 ####合规解决方案(CVE-2012-0507) 在Java 1.7.0版本的第3次更新中,对上面提到的构造函数进行了修改,使用Arrays.copyOf()方法替换了clone()方法。

    public AtomicReferenceArray(E[] array) { // Visibility guaranteed by final field guarantees this.array = Arrays.copyOf(  array, array.length, Object[].class);}`

    适用性

    使用clone()方法复制不可信的参数会给攻击者执行任意代码的机会。

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)