読者です 読者をやめる 読者になる 読者になる

XSS安全なMarkdownパーサーの要件と実装例

Markdownでユーザー入力を処理するならばXSS対策は不可欠であり、最高のXSS安全性を持つMarkdownパーサーを求めるならば少なくともDOMを生成して返すものでなければならない。

HTML文字列を返すものは基本的に安全性を担保せず呼び出す側に無害化の責務を負わせるものであり、仮にパーサー側でサニタイズを行って安全性を保証しようと試みても難しい。

ユーザー入力の無害化は特定の文字または文字列を禁止するブラックリスト方式ではほぼ不可能であり、一般的にホワイトリストで安全を確認した文字列をもとに自身で入出力を再構築するのがユーザー入力の唯一安全な受け入れ方法である。

これはHTMLとDOMのいずれでも可能だが、HTMLではエスケープの有無および種類の判断にヒューマンエラーが入りやすくDOMよりも安全性が劣る。エスケープの対象の識別は自身の部分的理解に基づくブラックリスト方式のフィルタリングであり、よほど範囲が限られ対応が確立されてない限りエスケープにより安全を確保することはできない。

一方DOMではdocument.createTextNodeelement.setAttributeを使うことでエスケープ(サニタイズ)処理をブラウザに丸投げできるのでエスケープの知識が必要なく、これでXSS脆弱性があればブラウザのバグというレベルにまで安全性を上げることができる。

仮にHTMLの出力を使うならばこのような安全なDOM構築を行うHTMLパーサーを噛ませる必要がある。加えて、有効だが危険な入力の除去も別途行う必要がある。

DOMを返すMarkdownパーサーはこの安全なHTMLパーサーを融合させたものであり、単体で安全性を担保する。ユーザー入力を受け入れる安全なMarkdownパーサーとはこのようなものでなければならない。よって、安全なMarkdownパーサーというものはサーバーでなくブラウザで動作するJavaScriptライブラリに限られる。

この要件を満たすMarkdownパーサーを探していたのだが、どうやらないようなので自身で実装することにした。

Securemark - secure markdown renderer working on browsers for user input data

このライブラリは上記の点を踏まえてXSS安全に設計、実装されており、100%安全で脆弱性のないMarkdownパーサーになっているはずだ。脆弱性の報告はもちろん歓迎する。上記のサイト上で攻撃コードを試せるので攻撃に成功したらIssueを投げてもらって構わない。

github.com


参考

shubs.io

Cross-site Scripting (XSS) - OWASP

[https://www.owasp.org/index.php/XSS(Cross_Site_Scripting)Prevention_Cheat_Sheet:title]

XSS Filter Evasion Cheat Sheet - OWASP