修改 Parsedown 代码过滤 XSS
PHP 有个开源的 Markdown 解析器 —— Parsedown
,很强大,但是在 XSS 过滤方面并不是做得特别好,我在用 Parsedown 对 Markdown 进行解析的时候,遇到了一些 XSS 过滤方面的问题。
Parsedown 会对 代码
区域内的 html 代码进行转义,代码
区域外的却不进行转义,如以下代码所示
<?php
include 'Parsedown.php';
$test = "```\n<script>alert('test')</script>\n```\n<script>alert('test')</script>";
$Parsedown = new Parsedown();
echo $Parsedown->text($test);
/**
* 得到结果是:
* <pre><code><script>alert('test')</script></code></pre>
* <script>alert('test')</script>
*
*/
这样,<script>alert('test')</script>
这句还是被成功执行了
既然如此,那我先自己给它转义一下
<?php
include 'Parsedown.php';
include 'com.func.php';
$test = "```\n<script>alert('test')</script>\n```\n<script>alert('test')</script>";
$test = htmlspecialchars($test, ENT_QUOTES);
$Parsedown = new Parsedown();
echo $Parsedown->text($test);
/**
* 得到结果是:
* <pre><code>&lt;script&gt;alert(&#039;test&#039;)&lt;/script&gt;</code></pre>
* <p><script>alert('test')</script></p>
*/
虽然 XSS 是被过滤掉了,但是代码
区域的内容就被转义了两次。
然后我发现 SF 的 Markdown 解析在 XSS 过滤方面就做得挺好的,例如这个页面,它的部分源码如下:
<p>我现在的代码是这样的<br>
<html><br>
<head><br><br>
<title>Untitled Document</title></p>
<pre><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></pre>
<p></head><br>
<body><br>
<input type="button" onClick="javascript:test();"></p>
<p></body><br>
</html></p>
<p>但这样是错误的<br>
我该怎样做呢</p>
后来尝试去看 Parsedown 的源码,终于找到了解决方案:
把 Parsedown 源码里所有(共三处)转义用的语句(如下所示)给注释掉
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
这句出现在了以下三个方法中:
protected function blockCodeComplete($Block)
、protected function blockFencedCodeComplete($Block)
、protected function inlineCode($Excerpt)
然后再修改一下
function text($text)
:function text($text) { #添加下面这行 $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); # Code... }
原项目我已经 fork 到我的 GitHub 上并且做了上述改动了,戳这里
后记:在遇到这个问题并多次尝试无解后,我在 Segmentfault 上提出了问题,因为一开始意外发错版块,导致首页没有显示出我这个问题,所以一直没有人来回答,最后暂时放下这个工作,去做了点其他事,几个小时后自己通过查看并修改 Parsedown 的代码就成功解决了 XSS 过滤的问题了。所以说有时候想不出来就先去做点其他事吧:-)