《Java安全编码标准》一2.2 IDS01-J验证前标准化字符串

    xiaoxiao2021-07-09  284

    2.2 IDS01-J验证前标准化字符串

    许多应用能够接收非受信的输入字符串,但需要对基于字符串的字符数据进行过滤和验证处理。例如,为了避免跨站脚本(Cross-Site Scripting, XSS)的安全漏洞问题,某些应用会采用在输入中禁止<script>标签的策略。这种黑名单式的机制是一种有效的安全策略,尽管它们对于输入验证和净化来说是不够的。这种方式的验证必须并且只能在对输入进行标准化以后进行。Java SE 6中的字符编码是基于Unicode编码标准4.0的[Unicode 2003] 。而在Java SE7中,其字符编码是基于Unicode编码标准6.0.0的[Unicode 2011]。根据Unicode编码标准[Davis 2008a]的15号附件,Unicode的标准化格式为:当在一个标准化形式中需要保留字符串时,它们需要确定同样的字符串有一个唯一的二进制表示。不能将KC和KD两种标准化形式盲目地应用于任意文本。因为它们会消除许多格式上的差别,它们可以用来防止在遗留字符集之间循环转换,同时,除非被格式化标记替代,否则它们可能会去除那些对文本语义来说很重要的差别。最好认为这些标准化格式就像大小写字符映射一样:在需要确认核心含义的某些场合下是有用的,但是,它也会对文本做出一些意想不到的修改。使用更为严格的字符集,可以让它们更为自由地应用到相关领域中。通常,对任意编码字符串进行输入验证的最适合的标准化格式是KC(NFKC)格式,因为标准化成KC可以将输入转换为等价的标准格式,这种格式可以安全地和需要的输入格式对比。

    2.2.1 不符合规则的代码示例

    如下所示的这个不符合规则的代码示例想要在进行标准化之前对字符串进行验证。结果是没有检测出应当拒绝的输入而使得验证逻辑无法进行,这是因为在进行尖括号检查时,代码不能分辨它的另一种Unicode表示方式。

    // String s may be user controllable // \uFE64 is normalized to < and \uFE65 is normalized to > using NFKC String s = "\uFE64" + "script" + "\uFE65"; // Validate Pattern pattern = Pattern.compile("[<>]"); // Check for angle brackets Matcher matcher = pattern.matcher(s); if (matcher.find()) { ??// Found black listed tag ??throw new IllegalStateException(); } else { ??// ... } // Normalize s = Normalizer.normalize(s, Form.NFKC);

    这个normalize()方法将Unicode文本转换为等价的组合或者分拆的形式,从而让对文本的搜索更为简单。因为该标准化方法支持在Unicode编码标准的15号附录中描述的标准标准化形式,所以被称为基于Unicode的标准化格式。

    2.2.2 符合规则的方案

    这个符合规则的解决方案在字符串验证前会将其进行标准化,它将字符串的另一种表示标准化为标准的尖括号。接着,输入验证可以正确地检测出恶意输入,并抛出IllegalStateException异常。

    String s = "\uFE64" + "script" + "\uFE65"; // Normalize s = Normalizer.normalize(s, Form.NFKC); // Validate Pattern pattern = Pattern.compile("[<>]"); Matcher matcher = pattern.matcher(s); if (matcher.find()) { ?// Found black listed tag ??throw new IllegalStateException(); } else { ??// ... }

    2.2.3 风险评估

    在标准化前进行输入验证会使攻击者有机会绕过数据过滤和其他安全机制。结果会导致执行任意代码。

    2.2.4 相关规范

    2.2.5 参考书目


    最新回复(0)