【修复总结】输入验证和表示 - 拒绝服务 - parseDouble

威胁描述

程序会调用解析 double 类型的方法,这会导致线程被挂起。

威胁说明

在实施 java.lang.Double.parseDouble() 及相关方法时出现漏洞,会导致在解析 [2^(-1022) - 2^(-1075) : 2^(-1022) - 2^(-1076)] 范围内的任意数字时挂起线程。此缺陷可被攻击者用于执行拒绝服务 (DoS) 攻击。

例 1:下列代码使用了易受攻击的方法。

Double d = Double.parseDouble(request.getParameter("d"));

攻击者可以发送 d 参数值位于该范围(例如 0.0222507385850720119e-00306)内的请求,致使程序在处理该请求时被挂起。

该漏洞在 Java 版本 6 Update 23 及更早版本中存在。Java 版本 6 Update 24 或更高版本不存在该漏洞。

修复建议

方案1:升级JDK至1.6 Update 24 以上,若JDK已经是1.6 Update 24以上,该类型漏洞可以关闭。

方案2:临时方案

public class ConvertDouble {

   private final static Pattern NUMBER_PATTERN = Pattern.compile("^([+-]?\\d*\\.?\\d*([eE][+-]?)?\\d*).*");

   public static double parseDouble(String value) {
        String normalString = normalizeDoubleString(value);
        int offset = normalString.indexOf('E');
        BigDecimal base;
        int exponent;
        if (offset == -1) {
            base = new BigDecimal(value);
            exponent = 0;
        } else {
            base = new BigDecimal(normalString.substring(0,offset));
            exponent = Integer.parseInt(normalString.charAt(offset+ 1) == '+'?
                normalString.substring(offset +2) :
                normalString.substring(offset +1));
        }
        returnbase.scaleByPowerOfTen(exponent).doubleValue();
   }
   public static String normalizeDoubleString(String strValue) {
        // Clean-up string representation so that it could be understood
        // by Java's BigDecimal. Not terribly efficient for now.
        // 1. MRI allows d and D as exponent separators
        strValue = strValue.replaceFirst("[edD]","E");
        // 2. MRI allows underscores anywhere
        strValue = strValue.replaceAll("_", "");
        // 3. MRI ignores the trailing junk
       strValue = NUMBER_PATTERN.matcher(strValue).replaceFirst("$1");
        return strValue;
    }
}

推荐阅读更多精彩内容