在Vaadin中使用Jsoup - 无法禁用转义?

时间:2013-10-28 16:15:17

标签: jsoup vaadin7

我正在尝试修改Vaadin发送到浏览器的引导程序Javascript。以下是有关此问题的Vaadin论坛链接: https://vaadin.com/forum#!/thread/4252604

Vaadin使用Jsoup所以我使用Jsoup API在Vaadin有效负载中找到正确的位置来修改Javascript。当我像这样使用Jsoup API时:

element.html(newHTML)

newHTML中的任何内容都会被转义。因此,例如,如果newHTML是:

alert("hi");

然后调用Jsoup API将导致:

alert("hi");

我以为我可以通过这样做来禁用这个Jsoup逃脱:

element.ownerDocument().outputSettings().escapeMode(...)

但ownerDocument()为null所以我不认为这是一个选项。 Jsoup是否有办法绕过这个限制,以便我可以获得具有双引号(“)和甚至打开/关闭标记括号(<,>)的Javascript以获得输出?

2 个答案:

答案 0 :(得分:0)

显然,

element.childNode(0).attr("data", html);
如果元素是“script”元素而 html 是Javascript源,那么

就可以了。

答案 1 :(得分:0)

我的解决方案是继承TextNode并覆盖执行转义的方法。

package org.jsoup.nodes;

public class UnescapedTextNode extends TextNode
{
    public UnescapedTextNode( final String text, final String baseUri )
    {
        super( text, baseUri );
    }

    @Override
    void outerHtmlHead(
        final StringBuilder accum,
        final int depth,
        final Document.OutputSettings out )
    {
        //String html = Entities.escape( getWholeText(), out ); // Don't escape!
        String html = getWholeText();
        if ( out.prettyPrint() &&
             parent() instanceof Element &&
             !Element.preserveWhitespace( parent() ) )
        {
             html = normaliseWhitespace( html );
        }
        if ( out.prettyPrint() &&
             ( ( siblingIndex() == 0 &&
                 parentNode instanceof Element &&
                 ( (Element)parentNode ).tag().formatAsBlock() &&
                   !isBlank() ) ||
                 ( out.outline() &&
                   siblingNodes().size() > 0 &&
                   !isBlank() ) ) )
        {
            indent( accum, depth, out );
        }
        accum.append( html );
    }
}

这几乎是TextNode.outerHtmlHead()的逐字副本(最初由Jonathan Hedley撰写)。我刚刚评论了逃逸的部分。这就是我使用它的方式:

// ... assuming head is of type Element and refers to the <head> of the document.
final String message = "Hello World!";
final String messageScript = "alert( \"" + message + "\" );";
final Element messageScriptEl = head.appendElement( "script" ).
    attr( "type", "text/javascript" );
final TextNode messageScriptTextNode = new UnescapedTextNode(
    messageScript,
    messageScriptEl.baseUri() );
messageScriptEl.appendChild( messageScriptTextNode );
// ... etc

此外,调用Document.toString()Document.outerHtml()会生成输出,其中包含未创建的脚本标记内的文本。即:

<script type="text/javascript">alert( "Hello World!" );</script>

而不是:

<script type="text/javascript">alert( &quot;Hello World!&quot; );</script>

以前发生过。

有两个&#39;陷阱&#39;我找到了:

  • UnescapedTextNode类需要由加载原始jsoup库的同一个类加载器加载。这是因为上面我已经覆盖了一个包私有方法,这是在JLS中规定的。 (感谢Jeff Sinclair提出的the article that pointed this out to me。相关的一点是

      

    当且仅当满足以下任一条件时,才能访问类或接口D的字段或方法R:

         
        
    • ...
    •   
    • R是包私有,由与D。
    • 相同的运行时包中的类声明   

    位于访问控制(5.4.4)下的 JVM规范中。

  • 这是一件非常冒险的事情,因为您有效地切断了阻止您将未经过处理的数据放入文档的安全网。确保您添加到此文本节点的任何来自应用程序用户的内容不包含html标记(特别是),或者您将在XSS,CSRF等方面遇到非常糟糕的时间。