如何安全地使用 Markdown 库?我需要做些什么来确保其输出可以安全地包含在我的网页中?
我想允许不受信任的用户输入内容(以 Markdown 格式)。我将使用 Markdown 处理器生成 HTML,并且我想在我的网页中包含该 HTML。我需要做些什么来确保这是安全的,而不是自己造成的 XSS 漏洞?我需要通过什么论据?我需要做任何预处理或后处理吗?如果相关,我正在使用 python-markdown 库。
如何安全地使用 Markdown 库?我需要做些什么来确保其输出可以安全地包含在我的网页中?
我想允许不受信任的用户输入内容(以 Markdown 格式)。我将使用 Markdown 处理器生成 HTML,并且我想在我的网页中包含该 HTML。我需要做些什么来确保这是安全的,而不是自己造成的 XSS 漏洞?我需要通过什么论据?我需要做任何预处理或后处理吗?如果相关,我正在使用 python-markdown 库。
推荐使用。简短的回答是:使用markdown(untrusted, safe_mode=remove, enable_attributes=False)
.
确保您拥有最新版本的 Markdown 库,因为旧版本存在一些安全问题。
您还可以通过 HTML 净化器(如 HTML Purifier)运行输出。
基本原理。 禁用enable_attributes
. 如果你设置了 Python markdown 库的最新开发版本,默认情况下会禁用enable_attributes
safe_mode
,但早期版本并没有这样做。因此,在大多数版本的 Markdown 库中,仅设置safe_mode
是不够的。如果你只是设置safe_mode
,结果是不安全的:
import markdown
>>> markdown.markdown("{@onclick=alert('hi')}some paragraph", safe_mode=True)
u'<p onclick="alert(\'hi\')">some paragraph</p>'
目前,修复程序仅存在于 git 中。在撰写本文时,最新发布的 Python Markdown 版本(2.1.1)仍然存在漏洞,除非您明确设置enable_attributes=False
. 因此,目前使用 Python Markdown 的许多系统可能存在漏洞,这似乎是合理的。
该文档可以更好地警告 Markdown 用户这些陷阱。它说诸如“您可能还想enable_attributes=False
在使用时设置safe_mode
”之类的内容,但没有透露不这样做会创建一个 XSS 漏洞,其中除了最新版本的库之外的所有版本。更高版本的文档说设置enable_attributes
“可能允许不受信任的用户将 JavaScript 注入您的文档”;更清楚地说,该设置enable_attributes
确实使用户能够将 Javascript 注入您的文档,因此如果 Markdown 可能来自不受信任的来源,则非常不安全。
怀疑。 也就是说,即使按照上面的建议使用它,我也不能 100% 确定结果是否安全。开发人员发表了如下评论:
“安全模式”是一个糟糕的名称选择,我们继续使用它来进行向后比较(旧代码仍然适用于我们的新版本)。它实际上是一种无标记模式。换句话说,这只是一种禁止原始 html 的方式,并不能保证安全。
这样的评论有点吓人。
在 Python Markdown 库的早期版本中,它的 HTML 清理对我来说看起来有点脆弱,所以我不确定我是否会信任早期版本的 Markdown 库,无论传递了什么标志。考虑以下:
>>> markdown.markdown("[Example](javascript://alert%28%22xss%22%29)", safe_mode=True)
u'<p><a href="javascript://alert%28%22xss%22%29">Example</a></p>'
javascript:
在我看来,通过 Markdown 的处理允许-style URL 是一个非常可疑的设计决定。感觉就像是在 XSS 的一跳、一跳和一跳之内。所缺少的只是一种打破 C++ 风格注释 (the //
) 的方法,游戏结束了。例如:
>>> markdown.markdown("[Example](javascript://\nalert%28%22xss%22%29)", safe_mode=True)
u'<p><a href="javascript:// alert%28%22xss%22%29">Example</a></p>'
我应该对没有浏览器执行该 Javascript 有多大信心?我不知道,但这并没有给我温暖、模糊的感觉。如果它是安全的,那只是盲目的运气。
幸运的是,如果您设置enable_attributes=False
. 但是请确保您设置enable_attributes=False
了 ,否则 Markdown 会退回到早期版本中发现的脆弱的 HTML 清理,我对该方案的安全性没有信心。
什么不该做。以下内容不安全:markdown(escape(untrusted))
.
[clickme](javascript:alert%28%22xss%22%29)
”打败。一般来说,将输入转义到 Markdown不是正确的方法;正确的方法是以适当的方式调用 Markdown(如果您想要额外的保护,也可能将 HTML 过滤器应用于其输出)。如果你使用 Django。如果您使用 Django,以下应该是使用 Markdown 的安全方法:
{{ untrusted | markdown:"safe" }}
从Django 1.4开始,这是安全的。当你传递"safe"
参数时,Django 现在特别支持 setsafe_mode
和 disable enable_attributes
。但请确保更新到 Django 1.4 或更高版本;在早期版本中,这种用法是不安全的。
仅 Markdown 不足以净化输出,因为它允许任意 HTML/Javascript 输入并且只是将其传递给未处理。
例如,这是一个有效的降价:
## heading
text
但也是这样:
## heading
text <script>alert('hello');</script>
从降价语法页面:
对于 Markdown 语法未涵盖的任何标记,您只需使用 HTML 本身。无需为它加上前缀或定界以表明您正在从 Markdown 切换到 HTML;您只需使用标签。
我刚刚使用 python-markdown 做了一个快速测试,它似乎确实以这种方式工作。
也就是说,鉴于 markdown 语法使用的字符集有限,在您将其提供给 markdown之前过滤您允许用户提供的字符集可能会更容易(例如,类似的东西a-zA-Z* #+:/&?=-_()>
),但即使这些可能足以混淆一些代码解析/编码它......所以我不确定你纯粹从你使用降价的事实中获得多少安全性。
经过进一步研究,我在 SO 上找到了这个答案,这似乎很明智。
然后我还进一步搜索并发现了safe_mode
开关(在此处和此处提到)。
快速测试似乎效果很好,但可能值得进一步研究......
>>> import markdown
>>> markdown.markdown("<script>alert('hello');</script> hello <strong>world</strong>")
u"<script>alert('hello');</script>\n\n<p>hello <strong>world</strong></p>"
>>> markdown.markdown("<script>alert('hello');</script> hello <strong>world</strong>", safe_mode=True)
u'<p>[HTML_REMOVED]</p>\n<p>hello [HTML_REMOVED]world[HTML_REMOVED]</p>'
文档页面上提供了 safe_mode 的完整选项集- 其中还提到enable_attributes
了False
为安全起见。