我正在使用OWASP Html Sanitizer来防止对我的网络应用程序进行XSS攻击。对于许多应该是纯文本的字段,Sanitizer的效果超出了我的预期。
例如:
HtmlPolicyBuilder htmlPolicyBuilder = new HtmlPolicyBuilder();
stripAllTagsPolicy = htmlPolicyBuilder.toFactory();
stripAllTagsPolicy.sanitize('a+b'); // return a+b
stripAllTagsPolicy.sanitize('foo@example.com'); // return foo@example.com
如果我的电子邮件地址等字段中包含+
,例如foo+bar@gmail.com
,我最终会在数据库中输入错误的数据。所以有两个问题:
+ - @
等字符本身是否真的有危险,是否真的需要编码? 问题2对我来说是更重要的答案。
答案 0 :(得分:3)
您可能希望使用ESAPI API过滤特定字符。虽然如果您想允许特定的HTML元素或属性,可以使用以下allowElements和allowAttributes。
//定义政策。
Function<HtmlStreamEventReceiver, HtmlSanitizer.Policy> policy
= new HtmlPolicyBuilder()
.allowElements("a", "p")
.allowAttributes("href").onElements("a")
.toFactory();
// Sanitize your output.
HtmlSanitizer.sanitize(myHtml, policy.apply(myHtmlStreamRenderer));
答案 1 :(得分:1)
XSS的危险在于,一个用户可能会在他的输入数据中插入html代码,以后您将这些代码插入发送给另一个用户的网页中。
如果您想要防止这种情况,原则上可以遵循两种策略。您可以在用户输入系统进入系统时删除所有危险字符,也可以在以后将其写回浏览器时对危险字符进行html编码。
第一个战略的例子:
用户输入数据(带有html代码)
第二种策略的例子:
第一种策略更简单,因为您通常不会经常使用它们来读取数据。但是,它也更难,因为它可能会破坏数据。如果您需要的数据不是稍后将其发送回浏览器(例如使用电子邮件地址来实际发送电子邮件),则特别困难。这使得在数据库中进行搜索,在pdf报告中包含数据,在电子邮件中插入数据等等更加困难。
另一种策略的优点是不会破坏输入数据,因此您可以更自由地在以后使用数据。但是,实际检查是否对发送到浏览器的所有用户提交的数据进行html编码可能更加困难。解决您的特定问题的方法是在您(或者如果)将该电子邮件地址放在网页上时对电子邮件地址进行html编码。
XSS问题是混合用户提交的数据和控制代码时出现的更普遍问题的示例。 SQL注入是同一问题的另一个例子。问题是用户提交的数据被解释为指令而不是数据。第三个不太为人所知的例子是,如果您在电子邮件中混合用户提交的数据。用户提交的数据可能包含电子邮件服务器解释为指令的字符串。这种情况下的“危险角色”是一个换行符,后跟“From:”。
不可能针对所有可能的控制字符或字符序列验证所有输入数据,这些字符可能在某种程度上被解释为将来某些潜在应用中的指令。对此唯一永久的解决方案是在实际使用该数据时实际清理所有可能不安全的数据。
答案 2 :(得分:1)
说实话,你应该真正针对所有用户提供的输入进行白名单。如果它是一个电子邮件地址,只需使用OWASP ESAPI或其他东西验证输入与其Validator和电子邮件正则表达式。
如果输入通过白名单,您应该继续将其存储在数据库中。将文本显示给用户时,应始终对其进行HTML编码。
OWASP不推荐您的黑名单方法,并且可能会被承诺攻击您的用户的人绕过。
答案 3 :(得分:0)
我知道我将在7年后回答问题,但也许对某人有用。 因此,基本上我同意你们的意见,出于安全原因,我们不应该允许使用特定字符(谢谢您介绍了本主题)。 但是,我正在做一个遗留的内部项目,该项目要求转义html字符,但出于我无法分辨的原因而使用“ @”(但这并不重要)。我的解决方法很简单:
private static final PolicyFactory PLAIN_TEXT_SANITIZER_POLICY = new HtmlPolicyBuilder().toFactory();
public static String toString(Object stringValue) {
if (stringValue != null && stringValue.getClass() == String.class) {
return HTMLSanitizerUtils.PLAIN_TEXT_SANITIZER_POLICY.sanitize((String) stringValue).replace("@", "@");
} else {
return null;
}
}
我知道它不干净,会创建其他String,但是我们非常需要此字符串。 因此,如果需要允许特定字符,则可以使用此替代方法。但是,如果您需要这样做,则您的应用程序可能设计不正确。