Heim  >  Artikel  >  Backend-Entwicklung  >  Parsedown 解析 Markdown 过滤 XSS 时应如何处理 html 转义

Parsedown 解析 Markdown 过滤 XSS 时应如何处理 html 转义

WBOY
WBOYOriginal
2016-06-06 20:37:522545Durchsuche

用 Parsedown 对 Markdown 进行解析的时候,遇到了一些 XSS 过滤方面的问题。

发现 Parsedown 会对 <code>代码 区域内的 html 代码进行转义,<code>代码区域外的却不进行转义,如以下代码所示

<code>PHP</code><code><?php include 'Parsedown.php';
$test = "```\n<script>alert('test')\n```\n<script>alert('test')</script>";
$Parsedown = new Parsedown();
echo $Parsedown->text($test);

/**
  * 得到结果是:
  * 

<pre class="brush:php;toolbar:false"><code><script>alert('test')</script></code>
* <script>alert('test')</script> * */

这样,<code><script>alert('test')</script>这句还是被成功执行了


既然如此,那我先自己给它转义一下

<code>PHP</code><code><?php include 'Parsedown.php';
include 'com.func.php';
$test = "```\n<script>alert('test')\n```\n<script>alert('test')</script>";
$test = htmlspecialchars($test, ENT_QUOTES);
$Parsedown = new Parsedown();
echo $Parsedown->text($test);

/**
  * 得到结果是:
  * 

<pre class="brush:php;toolbar:false"><code>&lt;script&gt;alert(&#039;test&#039;)&lt;/script&gt;</code>
*

<script>alert('test')</script>

*/

虽然 XSS 是被过滤掉了,但是<code>代码区域的内容就被转义了两次

然后我发现 SF 的 Markdown 好像是在后端就解析好的,例如这个页面,它的部分源码如下:

<code>html</code><code><br><br><p>我现在的代码是这样的<br>
<html><br>
<head><br><br>
    <title>Untitled Document</title></p>





<pre class="brush:php;toolbar:false"><code><script>
    function test(){
        <?php
            $conn = mysql_connect("localhost", "username", "123123");
            mysql_select_db("username", $conn);
            mysql_query("INSERT INTO ChargerTogether (Chat) VALUES ('test')");
            $result= mysql_query("SELECT *FROM ChargerTogether");

            echo "<p> {$result} </p>>";
        ?>
    }

</script>
</code>




但这样是错误的
我该怎样做呢

这里的转义就做得很好。


我想到的解决方案是:先转义,再用 Parsedown 进行解析,接着正则匹配出解析后 <code><code> 内的代码,对其进行反转义(一次)。

不知道是不是还有别的更好的转义函数,或者说 有没有其他的能够过滤 XSS 的 Markdown 解析类

P.S. 我在 github 上面找到有个 markdown-js。用这个东西的话可以把经<code>htmlspecialchars(()转义后的字符串直接输出到一个 <code>textaera 里,它能够正确地解析。虽然我可以把那个文本框隐藏起来,但是如果需要输出很多段 Markdown (帖子有很多回复)的话,那可不是一个好的解决方案啊!

回复内容:

用 Parsedown 对 Markdown 进行解析的时候,遇到了一些 XSS 过滤方面的问题。

发现 Parsedown 会对 <code>代码 区域内的 html 代码进行转义,<code>代码区域外的却不进行转义,如以下代码所示

<code>PHP</code><code><?php include 'Parsedown.php';
$test = "```\n<script>alert('test')\n```\n<script>alert('test')</script>";
$Parsedown = new Parsedown();
echo $Parsedown->text($test);

/**
  * 得到结果是:
  * 

<pre class="brush:php;toolbar:false"><code><script>alert('test')</script></code>
* <script>alert('test')</script> * */

这样,<code><script>alert('test')</script>这句还是被成功执行了


既然如此,那我先自己给它转义一下

<code>PHP</code><code><?php include 'Parsedown.php';
include 'com.func.php';
$test = "```\n<script>alert('test')\n```\n<script>alert('test')</script>";
$test = htmlspecialchars($test, ENT_QUOTES);
$Parsedown = new Parsedown();
echo $Parsedown->text($test);

/**
  * 得到结果是:
  * 

<pre class="brush:php;toolbar:false"><code>&lt;script&gt;alert(&#039;test&#039;)&lt;/script&gt;</code>
*

<script>alert('test')</script>

*/

虽然 XSS 是被过滤掉了,但是<code>代码区域的内容就被转义了两次

然后我发现 SF 的 Markdown 好像是在后端就解析好的,例如这个页面,它的部分源码如下:

<code>html</code><code><br><br><p>我现在的代码是这样的<br>
<html><br>
<head><br><br>
    <title>Untitled Document</title></p>





<pre class="brush:php;toolbar:false"><code><script>
    function test(){
        <?php
            $conn = mysql_connect("localhost", "username", "123123");
            mysql_select_db("username", $conn);
            mysql_query("INSERT INTO ChargerTogether (Chat) VALUES ('test')");
            $result= mysql_query("SELECT *FROM ChargerTogether");

            echo "<p> {$result} </p>>";
        ?>
    }

</script>
</code>




但这样是错误的
我该怎样做呢

这里的转义就做得很好。


我想到的解决方案是:先转义,再用 Parsedown 进行解析,接着正则匹配出解析后 <code><code> 内的代码,对其进行反转义(一次)。

不知道是不是还有别的更好的转义函数,或者说 有没有其他的能够过滤 XSS 的 Markdown 解析类

P.S. 我在 github 上面找到有个 markdown-js。用这个东西的话可以把经<code>htmlspecialchars(()转义后的字符串直接输出到一个 <code>textaera 里,它能够正确地解析。虽然我可以把那个文本框隐藏起来,但是如果需要输出很多段 Markdown (帖子有很多回复)的话,那可不是一个好的解决方案啊!

刚刚把 Parsedown 源码里所有(共三处)转义用的语句(如下所示)给注释掉,

<code>PHP</code><code>$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
</code>

这句出现在了以下三个方法中:
<code>protected function blockCodeComplete($Block)、<code>protected function blockFencedCodeComplete($Block)、<code>protected function inlineCode($Excerpt)

然后再修改一下 <code>function text($text):

<code>function text($text)
    {
        #添加下面这行
        $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
        # Code...
    }
</code>

这么做虽然说是解决了,但是可能不是最完美的解决方案,还请各位大大继续提供更好的方案~

我也遇到这个问题了,后来发现,只要把代码块外面的 <script></script> 写成<script></script>/>即可,这样就会转换成文字了。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn