6

I've got a problem in my current project: Users can send an email using a textarea. We allow the user to put in whatever they want, and thus some HTML for formatting. For example, the user should be allowed to use the <b> tag for bold text.

After completing their email, the user should be able to view a preview of their email dynamically.

There is a slight problem though, how can I avoid XSS hacks when the preview is being displayed?

You can ofcourse strip them using underscore.js, but that wouldn't format their preview.

So I have forbidden all HTML tags for now, and only allowed tags like <hr>, <b>, etc.

What do you think about this solution? Is it secure enough?

4

5 回答 5

7

为了防止应用程序受到 XSS 攻击,我通常使用以下规则:

  1. 确定应用程序的安全级别。
    有几种工具可以保护您的应用程序,因为OWASP工具提供了更好的安全性:ESAPIAntySami
    注意:使用 Sanitization 并不能保证过滤所有恶意代码,因此工具可能或多或少是安全的。

  2. 了解您是否需要在客户端、服务器或双方上执行清理。在大多数情况下,在服务器端执行此操作就足够了。

  3. 了解您是否需要保留 html 标签(以及您需要保留哪些标签)。如前所述,不允许 html 标签是更安全的解决方案。

基于此,您可以找到正确的决定。
1. 我个人使用jSoup进行服务器代码清理。对我来说,这是一个很好的工具。
通常为了检查输入漏洞,我使用以下向量:

';alert(String.fromCharCode(88,83,83))//\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\";alert(String.fromCharCode(88,83,83))//--></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
  1. 如果您需要在客户端防止 XSS,您可以使用以下工具:
    a) JSSANItazer似乎有点过时
    b) Dust - 由 twitter 维护;

这些工具可以很容易地让你清理你的输入,主要是回答你的问题。

上面提到的服务器端工具。

关于第三点。如果您不需要处理 html 标签,您可以轻松地在服务器端使用 ESAPI,在客户端使用ESAPI4JS。据我了解,它对你不起作用。

当我阅读您的任务时,我了解到您正在存储电子邮件,因此在您的情况下,需要清理服务器端的输入(使用其中一种工具),并且根据您是否在客户端添加它。您只需要决定是在 UI 端添加另一个清理还是在服务器上呈现您的“预览页面”。

于 2013-11-13T00:39:26.937 回答
1

避免大多数 XSS 攻击的最佳方法是:

这两者一起将使您的网站非常强大

于 2013-11-06T22:58:23.970 回答
1

你当然可以一直切换到使用BB 代码,使用与表单相同的解析器进行预览,然后在发送时解析 ubb 代码服务器端。

如果您想解析 BB 代码客户端以进行预览,请参阅这篇文章,而本文则用于解析 BB 代码服务器端,假设您使用 PHP 发送邮件。

于 2013-11-06T22:50:06.567 回答
0

我认为由于在电子邮件客户端中工作的标签是一个相对较小(但仍然相当大)的列表,您可能希望使用标签白名单,类似于您现在正在做的事情。除去标签但您允许的标签将是一个相对复杂的正则表达式,但我认为这是您可以允许某些标签而不是其他标签的唯一方法。这不是万无一失的,因为标签的删除可以用来创建新的标签,例如在我下面的输入中,假设是不允许的,你把它去掉:

<<script>script language="javascript">Do something bad</<script>script>

您可能想探索使用 markdown 或一些类似的语法,您可以在服务器端将其转换为一些有效的 HTML。

http://daringfireball.net/projects/markdown/

这样,他们可以使用一小部分格式降价,您可以在服务器端替换它们。

于 2013-11-06T22:55:04.297 回答
-1

如果你想通过允许一些标签来防止服务器端的 XSS 攻击,你可以使用 OWASP HTMLSanitizer(OWASP antisamy 现在不活动),也可以制定自己的规则。

  • HTML sanitizer 项目页面:
    https ://www.owasp.org/index.php/OWASP_Java_HTML_Sanitizer_Project
  • 示例规则 - Ebay 规则:
    https ://github.com/OWASP/java-html-sanitizer/blob/master/src/main/java/org/owasp/html/examples/EbayPolicyExample.java

    https://github.com/OWASP/java-html-sanitizer/blob/master/src/main/java/org/owasp/html/examples/EbayPolicyExample.java
    public static final PolicyFactory POLICY_DEFINITION = new HtmlPolicyBuilder()
          .allowAttributes("id").matching(HTML_ID).globally()
          .allowAttributes("class").matching(HTML_CLASS).globally()
          .allowAttributes("lang").matching(Pattern.compile("[a-zA-Z]{2,20}"))
              .globally()
          .allowAttributes("title").matching(HTML_TITLE).globally()
          .allowStyling()
          .allowAttributes("align").matching(ALIGN).onElements("p")
          .allowAttributes("for").matching(HTML_ID).onElements("label")
          .allowAttributes("color").matching(COLOR_NAME_OR_COLOR_CODE)
              .onElements("font")
          .allowAttributes("face")
              .matching(Pattern.compile("[\\w;, \\-]+"))
              .onElements("font")
          .allowAttributes("size").matching(NUMBER).onElements("font")
          .allowAttributes("href").matching(ONSITE_OR_OFFSITE_URL)
              .onElements("a")
          .allowStandardUrlProtocols()
          .allowAttributes("nohref").onElements("a")
          .allowAttributes("name").matching(NAME).onElements("a")
          .allowAttributes(
              "onfocus", "onblur", "onclick", "onmousedown", "onmouseup")
              .matching(HISTORY_BACK).onElements("a")
          .requireRelNofollowOnLinks()
          .allowAttributes("src").matching(ONSITE_OR_OFFSITE_URL)
              .onElements("img")
          .allowAttributes("name").matching(NAME)
              .onElements("img")
          .allowAttributes("alt").matching(PARAGRAPH)
              .onElements("img")
          .allowAttributes("border", "hspace", "vspace").matching(NUMBER)
              .onElements("img")
          .allowAttributes("border", "cellpadding", "cellspacing")
              .matching(NUMBER).onElements("table")
          .allowAttributes("bgcolor").matching(COLOR_NAME_OR_COLOR_CODE)
              .onElements("table")
          .allowAttributes("background").matching(ONSITE_URL)
              .onElements("table")
          .allowAttributes("align").matching(ALIGN)
              .onElements("table")
          .allowAttributes("noresize").matching(Pattern.compile("(?i)noresize"))
              .onElements("table")
          .allowAttributes("background").matching(ONSITE_URL)
              .onElements("td", "th", "tr")
          .allowAttributes("bgcolor").matching(COLOR_NAME_OR_COLOR_CODE)
              .onElements("td", "th")
          .allowAttributes("abbr").matching(PARAGRAPH)
              .onElements("td", "th")
          .allowAttributes("axis", "headers").matching(NAME)
              .onElements("td", "th")
          .allowAttributes("scope")
              .matching(Pattern.compile("(?i)(?:row|col)(?:group)?"))
              .onElements("td", "th")
          .allowAttributes("nowrap")
              .onElements("td", "th")
          .allowAttributes("height", "width").matching(NUMBER_OR_PERCENT)
              .onElements("table", "td", "th", "tr", "img")
          .allowAttributes("align").matching(ALIGN)
              .onElements("thead", "tbody", "tfoot", "img",
                               "td", "th", "tr", "colgroup", "col")
          .allowAttributes("valign").matching(VALIGN)
              .onElements("thead", "tbody", "tfoot",
                              "td", "th", "tr", "colgroup", "col")
          .allowAttributes("charoff").matching(NUMBER_OR_PERCENT)
              .onElements("td", "th", "tr", "colgroup", "col",
                              "thead", "tbody", "tfoot")
          .allowAttributes("char").matching(ONE_CHAR)
              .onElements("td", "th", "tr", "colgroup", "col",
                               "thead", "tbody", "tfoot")
          .allowAttributes("colspan", "rowspan").matching(NUMBER)
              .onElements("td", "th")
          .allowAttributes("span", "width").matching(NUMBER_OR_PERCENT)
              .onElements("colgroup", "col")
          .allowElements(
              "a", "label", "noscript", "h1", "h2", "h3", "h4", "h5", "h6",
              "p", "i", "b", "u", "strong", "em", "small", "big", "pre", "code",
              "cite", "samp", "sub", "sup", "strike", "center", "blockquote",
              "hr", "br", "col", "font", "map", "span", "div", "img",
              "ul", "ol", "li", "dd", "dt", "dl", "tbody", "thead", "tfoot",
              "table", "td", "th", "tr", "colgroup", "fieldset", "legend")
          .toFactory();
    
于 2016-01-19T04:04:47.353 回答