web-dev-qa-db-ja.com

Markdownを安全に使用するにはどうすればよいですか?

Markdownライブラリを安全に使用するにはどうすればよいですか?出力をWebページに安全に含めることができるようにするには、何をする必要がありますか?

信頼できないユーザーが(Markdown形式で)コンテンツを入力できるようにします。 Markdownプロセッサを使用してHTMLを生成します。そのHTMLを自分のWebページに含めたいのですが。これが安全で、自発的なXSSの脆弱性ではないことを確認するために何をする必要がありますか?どのような引数を渡す必要がありますか?前処理または後処理は必要ですか?必要に応じて、python-markdownライブラリを使用しています。

45
D.W.

推奨される使用法。短い答えは、markdown(untrusted, safe_mode=remove, enable_attributes=False)を使用することです。

古いバージョンにはセキュリティ上の問題があるため、Markdownライブラリの最新バージョンを使用していることを確認してください。

HTML PurifierなどのHTMLサニタイザーを介して出力を実行することもできます。

根拠。_enable_attributes_を無効にすることをお勧めします。 Pythonマークダウンライブラリの最新の開発バージョンは、デフォルトで 無効にする_enable_attributes_を設定すると_safe_mode_ になりますが、以前のバージョンはそうしませんでした。したがって、_safe_mode_を設定するだけで Markdownライブラリのほとんどのバージョンでは十分ではありません 。 _safe_mode_を設定しただけの場合、結果は安全ではありません。

_import markdown
>>> markdown.markdown("{@onclick=alert('hi')}some paragraph", safe_mode=True)
u'<p onclick="alert(\'hi\')">some paragraph</p>'
_

現時点では、修正はgitにのみ存在します。この記事の執筆時点では、_enable_attributes=False_を明示的に設定しない限り、Python Markdown(2.1.1)の最新リリースバージョンは引き続き脆弱です。したがって、現在Python Markdownを使用している多くのシステムが脆弱である可能性があります。

ドキュメンテーションは、これらの落とし穴についてMarkdownのユーザーに警告するのに適しています。 「_enable_attributes=False_の使用時に_safe_mode_を設定することもできます。ドキュメントの新しいバージョンでは、_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>'
_

Markdownの処理を通じて_javascript:_スタイルのURLを許可することは、設計上、かなり疑わしい決定のように思えます。これは、XSSのホップ、スキップ、ジャンプの範囲内にあるように感じます。不足しているのは、C++スタイルのコメント(_//_)から抜け出す方法であり、ゲームオーバーです。例えば:

_>>> markdown.markdown("[Example](javascript://\nalert%28%22xss%22%29)", safe_mode=True)
u'<p><a href="javascript://&#10;alert%28%22xss%22%29">Example</a></p>'
_

どのJavaScriptもそのJavascriptを実行しないことをどの程度確信できますか?わからないけど、あたたかくてぼんやりした気持ちにならない。それが安全であれば、それはただの不運です。

さいわい、Markdownの最新リリースバージョンでは、_enable_attributes=False_を設定すると、スクリプトのフィルタリングが厳しくなります。ただし、必ず_enable_attributes=False_を設定してください。そうしないと、Markdownが以前のバージョンで見つかった脆弱なHTMLのサニタイズにフォールバックします。そのスキームのセキュリティには自信がありません。

すべきでないこと。以下は安全ではありません:markdown(escape(untrusted))

  • 最初に入力をエスケープすると、すべてのHTMLが削除され、この使用法が安全になると考えるかもしれません。実際、これは一部のシステムで使用され、一部のシステムで推奨されています。ただし、URLを安全にするにはエスケープでは不十分なので、実際には安全ではありません。たとえば、Markdownのこの使用法は、「[clickme](javascript:alert%28%22xss%22%29)」によって無効にすることができます。一般的に、Markdownへの入力のエスケープは 正しいアプローチではない ;です。適切な方法は、適切な方法でMarkdownを呼び出すことです(さらに保護が必要な場合は、出力にHTMLフィルターを適用することもできます)。

Djangoを使用する場合。Djangoを使用する場合、Markdownを使用する安全な方法は次のとおりです。

_{{ untrusted | markdown:"safe" }}
_

Django 1.4 以降、これは安全です。 _"safe"_引数を渡すと、Djangoは、_safe_mode_を設定して_enable_attributes_を無効にする特別なサポートを追加しました。ただし、必ずDjango 1.4以降に更新してください。以前のバージョンでは、 この使用法は安全ではありませんでした

16
D.W.

Markdownだけでは、任意のHTML/Javascript入力を許可し、単に処理せずに渡すため、出力をサンタイズするのに十分ではありません。

例えば。これは有効なマークダウンです:

_## heading

text
_

しかしこれも:

_## heading

text <script>alert('hello');</script>
_

markdown syntax page から:

Markdownの構文でカバーされていないマークアップについては、単にHTML自体を使用します。 MarkdownからHTMLに切り替えることを示すために、前置きや区切りを付ける必要はありません。タグを使用するだけです。

私はpython-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に設定することについても言及しています。

13
Yoav Aner