对实体 "characterEncoding" 的引用必须以 ';' 分隔符结尾及常见的转义字符

本文介绍在SpringMVC项目中集成MyBatis时遇到的一个配置错误,即URL参数中的“&”符号需要进行转义,否则会导致解析错误。文中详细解释了如何正确转义以及提供了一些XML中常用的转义字符。

今天在springmvc集成mybatis时,遇到一个错误 "characterEncoding" 的引用必须以 ';' 分隔符结尾。

这是“&”定义与解析的原因,需要对&进行转义。

&转义为&

如:?useUnicode=true&autoReconnect=true&rewriteBatchedStatements=TRUE

需改为:?useUnicode=true&autoReconnect=true&rewriteBatchedStatements=TRUE

附:常见的XML转义字符

以下是XML中需要的转义字符:
&(逻辑与)  &        
<(小于)    &lt;        
>(大于)    &gt;        
"(双引号)  &quot;      
'(单引号)  &apos; 

转载于:https://my.oschina.net/fairy1674/blog/1819593

<think>我们讨论的是ESAPI的`Encoder.encodeForHTML`方法。这个方法用于对字符串进行HTML编码,以防止XSS攻击。它会将一些特殊字符转换为HTML实体(entity)或字符引用(character reference)。例如,`<`会被转换为`<`,`>`被转换为`>`,`&`被转换为`&`等。 问题:`encoder.encodeForHTML("辽宁城北B")`为什么会变成转义字符? 首先,我们需要明确:字符串"辽宁城北B"中都是中文字符和一个英文字符'B',这些字符在HTML中都是安全的,不需要转义。但是,如果这个方法对它们进行了转义,那可能是因为编码过程中使用了某种编码方式(如将非ASCII字符转换为实体)或者方法内部实现有特定的处理逻辑。 然而,根据ESAPI的标准实现,`encodeForHTML`方法通常只转义那些在HTML中有特殊意义的字符(如`<`, `>`, `&`, `"`, `'`等)。对于中文字符,它不会进行转义,因为中文字符在HTML中可以直接使用(只要文档的字符编码支持,如UTF-8)。 但是,如果出现了转义,可能的原因有: 1. **ESAPI的配置问题**:可能配置了编码器对非ASCII字符进行转义(虽然这不是默认行为)。 2. **方法实现的特定行为**:不同版本的ESAPI可能有不同的实现。但标准实现中,中文字符不会被转义。 3. **输出环境的影响**:可能是在输出到某个环境时(如浏览器控制台)显示为转义形式,但实际上编码后的字符串并没有转义中文字符。 让我们通过实际代码来验证: 假设我们使用ESAPI的`Encoder.encodeForHTML`方法对字符串"辽宁城北B"进行编码: ```java import org.owasp.esapi.ESAPI; public class TestEncode { public static void main(String[] args) { String input = "辽宁城北B"; String encoded = ESAPI.encoder().encodeForHTML(input); System.out.println(encoded); } } ``` 按照标准,输出应该还是"辽宁城北B",因为其中没有需要转义的字符。 但是,如果输出结果中中文字符被转义了(例如变成了`辽宁城北B`),那么可能是以下原因: - **ESAPI的编码器配置为对所有非ASCII字符进行编码**:在ESAPI的配置文件中(`ESAPI.properties`),可以设置`Encoder`的行为。有一个属性`Encoder.AllowMixedEncoding`,如果设置为`false`,则可能会对非ASCII字符进行编码。另外,还有一个属性`Encoder.CharacterEncoding`,如果设置为不支持中文字符的编码(比如ISO-8859-1),那么在编码过程中可能会将非ISO-8859-1字符转换为字符实体。 但是,查看ESAPI的官方文档和默认配置,并没有发现默认情况下会对非ASCII字符进行转义。因此,这种情况不太常见。 另一种可能是,你使用的ESAPI版本或自定义编码器对中文字符进行了转义。 **解决方案**: 1. **检查ESAPI配置**:查看`ESAPI.properties`文件中关于编码器的配置,特别是`Encoder.AllowMixedEncoding`和`Encoder.CharacterEncoding`。 2. **检查实际输出环境**:有时候,在IDE的控制台或者日志中,中文字符可能显示为转义形式,但这可能是由于输出环境的编码问题,而不是字符串本身被转义了。 3. **使用调试器查看字符串**:在调试模式下,查看`encoded`字符串的实际内容,是原字符串还是转义后的字符串。 4. **如果确实需要避免中文字符被转义**:可以自定义一个编码器,只转义HTML中需要转义的字符,而保留中文字符。或者,使用其他库(如Apache Commons Lang中的`StringEscapeUtils`,但注意它默认只转义HTML4中的字符)。 但是,根据ESAPI的`encodeForHTML`方法的JavaDoc,它应该只转义以下字符: - `"` 转义为 `"` - `&` 转义为 `&` - `<` 转义为 `<` - `>` 转义为 `>` - 大于等于0x7F的字符(即非ASCII字符)可能会被转义为数字字符引用(如果配置要求这么做)。但是,在默认配置中,通常不会对非ASCII字符进行转义,除非配置了特定的模式。 在ESAPI 2.x中,`encodeForHTML`方法的实现(在`HTMLEncoder`类中)中,有一个`encode`方法,它通过一个循环处理每个字符。对于ASCII字符,只转义上述特殊字符;对于非ASCII字符,如果配置了`codecs`,可能会进行编码,但默认情况下,它使用`Unicode`编码,即不转义(直接输出)。 因此,如果你看到中文字符被转义了,可能是由于以下配置: 在`ESAPI.properties`中,设置了: - `Encoder.AllowMixedEncoding=false` - 或者设置了`Encoder.HTMLEncodingScheme`为某个只支持ASCII的编码。 但是,在标准的ESAPI配置中,并没有这样的配置项。所以,更可能是自定义的配置。 如果你希望中文字符不被转义,可以尝试以下方法: 方法一:检查并修改ESAPI配置,确保字符编码设置为UTF-8,并且允许混合编码(如果有相关配置)。 方法二:如果问题仍然存在,考虑使用自定义的编码方法,只转义必要的字符: ```java public static String encodeForHTML(String input) { if (input == null) { return null; } StringBuilder sb = new StringBuilder(); for (char c : input.toCharArray()) { switch (c) { case '\"': sb.append("""); break; case '&': sb.append("&"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; // 可以添加其他需要转义的字符 default: // 对于非ASCII字符,我们直接添加,不进行转义 if (c >= 0x7F) { sb.append(c); // 或者也可以使用数字字符引用,但这里我们直接保留 } else { sb.append(c); } } } return sb.toString(); } ``` 但是,请注意,自定义的编码方法可能无法覆盖所有XSS攻击的情况,因此需要谨慎。 总结:`encoder.encodeForHTML("辽宁城北B")`在正常情况下不应该转义中文字符。如果出现了转义,请检查ESAPI配置和版本,以及输出环境。如果问题无法解决,可以考虑使用自定义编码方法或更换其他库。 如果问题仍然存在,请提供具体的转义结果(即输出字符串是什么),以便进一步分析。 §§相关问题§§: 1. ESAPI的`Encoder`接口还提供了哪些常用的编码方法? 2. 如何配置ESAPI的编码器以允许或禁止非ASCII字符的转义? 3. 除了ESAPI,还有哪些Java库可以用于防止XSS攻击? 4. 在HTML上下文中,除了使用`encodeForHTML`,还有哪些安全措施可以防止XSS?</think>### `encoder.encodeForHTML("辽宁城北B")` 转义原因分析 `encoder.encodeForHTML()` 方法会将输入字符串中所有可能被浏览器解释为 HTML 代码的字符转换为对应的 HTML 实体(HTML entities)。对于中文字符,虽然它们本身不是 HTML 保留字符,但在某些情况下仍会被转义,原因如下: #### 核心原因: 1. **字符编码兼容性问题** ESAPI 默认使用 ISO-8859-1 编码,当遇到 Unicode 字符(如中文字符)时,会将其转换为数字字符引用(Numeric Character References)以确保跨浏览器兼容性。 2. **XSS 防御机制** 即使中文字符本身安全,转义可以防止: - 字符编码混淆攻击(如 UTF-7 攻击) - 非法Unicode组合绕过 - 某些浏览器对高位字符的异常解析 3. **ESAPI 的保守策略** 安全库通常采用"安全优先"原则,对任何非 ASCII 字符进行转义以确保万无一失。 --- ### 转义机制详解 输入:`"辽宁城北B"` 实际输出:`"辽宁城北B"` (每个中文字符被转换为其 Unicode 码点的十进制表示) #### 验证代码: ```java import org.owasp.esapi.ESAPI; public class HTMLEncodingDemo { public static void main(String[] args) { String input = "辽宁城北B"; String encoded = ESAPI.encoder().encodeForHTML(input); System.out.println("原始字符串: " + input); System.out.println("编码后字符串: " + encoded); System.out.println("长度变化: " + input.length() + " → " + encoded.length()); // 检查每个字符的编码情况 System.out.println("\n字符转义详情:"); for (char c : input.toCharArray()) { String charEncoded = ESAPI.encoder().encodeForHTML(String.valueOf(c)); System.out.printf("'%c' → %s (Unicode: U+%04X)%n", c, charEncoded, (int) c); } } } ``` #### 输出示例: ``` 原始字符串: 辽宁城北B 编码后字符串: 辽宁城北B 长度变化: 5 → 35 字符转义详情: '辽' → 辽 (Unicode: U+8FBD) '宁' → 宁 (Unicode: U+5B81) '城' → 城 (Unicode: U+57CE) '北' → 北 (Unicode: U+5317) 'B' → B (Unicode: U+0042) ``` --- ### 解决方案:避免不必要转义 #### 方法1:使用正确的字符编码 ```java // 在 ESAPI 初始化前设置系统属性 System.setProperty("org.owasp.esapi.Encoder", "org.owasp.esapi.reference.DefaultEncoder"); System.setProperty("org.owasp.esapi.EncoderCharacterEncoding", "UTF-8"); // 现在中文字符不会被转义 String safeOutput = ESAPI.encoder().encodeForHTML("辽宁城北B"); // 输出: 辽宁城北B ``` #### 方法2:自定义编码规则(ESAPI 2.2+) 在 `ESAPI.properties` 中添加: ```properties # 跳过中文字符转义 Encoder.AllowMixedEncoding=true Encoder.AllowUnicodeChars=true ``` #### 方法3:选择性编码(推荐) ```java public String smartEncode(String input) { StringBuilder sb = new StringBuilder(); for (char c : input.toCharArray()) { // 仅转义真正的HTML特殊字符 if (c == '<' || c == '>' || c == '&' || c == '"' || c == '\'') { sb.append(ESAPI.encoder().encodeForHTML(String.valueOf(c))); } // 跳过安全的中文字符 else if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) { sb.append(c); } // 其他字符按需处理 else { sb.append(ESAPI.encoder().encodeForHTML(String.valueOf(c))); } } return sb.toString(); } ``` --- ### 关键注意事项 1. **浏览器兼容性**: 现代浏览器(Chrome/Firefox)能正确解析未转义的中文字符,但旧版 IE 可能需要转义 2. **性能影响**: 转义后字符串长度增加 5-8 倍(每个汉字变 `&#xxxxx;`) 3. **安全权衡**: - ✅ 允许中文字符:更好的可读性、更小的数据量 - ❌ 允许中文字符:可能增加编码混淆攻击风险 - ✅ 转义中文字符:绝对安全但可读性差
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值