WMD エディターのプレビュー HTML をサーバー側の HTML 検証と調整します (例:JavaScript コードは埋め込まれていません)
-
26-09-2019 - |
質問
スタック オーバーフローに関する質問は数多くあります (例: ホワイトリスト、C# の WMD 制御による XSS の防止 そして WMD マークダウンとサーバーサイド) WMD エディターによって生成された Markdown をサーバー側でスクラブして、生成された HTML に悪意のあるスクリプトが含まれていないことを確認する方法について説明します。
<img onload="alert('haha');"
src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" />
しかし、クライアント側でもその穴をふさぐ良い方法が見つかりませんでした。もちろん、クライアント検証はサーバー上でのスクラブ検証に代わるものではありません。誰でもクライアントになりすまして厄介な Markdown を POST できるからです。また、サーバー上で HTML をスクラブしている場合、攻撃者は不正な HTML を保存できないため、後から他の人がその HTML を参照して、Cookie が盗まれたり、不正なスクリプトによってセッションがハイジャックされたりすることはありません。したがって、WMD プレビュー ペインでもスクリプトなしルールを強制する価値がないかもしれないという正当なケースがあります。
しかし、攻撃者が悪意のある Markdown をサーバーに侵入させる方法を見つけたと想像してください (例:別のサイトからの侵害されたフィード、または XSS バグが修正される前に追加されたコンテンツ)。マークダウンを HTML に変換するときに適用されるサーバー側のホワイトリストは、通常、その不正なマークダウンがユーザーに表示されるのを防ぎます。しかし、攻撃者が誰かにページを編集させることができた場合 (例:悪意のあるエントリのリンクが壊れているという別のエントリを投稿し、誰かに修正を依頼することによって)、ページを編集した人は誰でも Cookie をハイジャックされます。これは確かに特殊なケースですが、それでも防御する価値があるかもしれません。
また、サーバーが許可するものとは異なる HTML をクライアントのプレビュー ウィンドウで許可することは、おそらく悪い考えです。
Stack Overflow チームは、WMD に変更を加えてこの穴を塞ぎました。彼らはどうやってそれをしたのでしょうか?
[注記:私はすでにこれを理解していましたが、いくつかのトリッキーな JavaScript デバッグが必要だったので、同じことをしたいと考えている他の人を助けるために、ここで私自身の質問に答えています。.
解決
考えられる修正の 1 つは、wmd.js にあります。 pushPreviewHtml()
方法。元のコードは次のとおりです GitHub 上の WMD のスタック オーバーフロー バージョン:
if (wmd.panels.preview) {
wmd.panels.preview.innerHTML = text;
}
これをスクラブ コードに置き換えることができます。これは、Stack Overflow が使用するコードの適応です。 この投稿への返信として, 、タグのホワイトリストに制限され、IMG および A 要素の場合は属性のホワイトリストに制限されます (しかも特定の順序で!)。メタスタックオーバーフローの投稿を参照してください。 スタック オーバーフロー、サーバー フォールト、およびスーパー ユーザーではどの HTML タグが許可されますか? ホワイトリストの詳細については、こちらをご覧ください。
注記:このコードは確かに改善できます。ホワイトリストに登録された属性を任意の順序で許可します。また、mailto も禁止されます。URL は、インターネット サイトではおそらく良いことですが、独自のイントラネット サイトでは最良のアプローチではない可能性があります。
if (wmd.panels.preview) {
// Original WMD code allowed JavaScript injection, like this:
// <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" onload="alert('haha');"/>
// Now, we first ensure elements (and attributes of IMG and A elements) are in a whitelist,
// and if not in whitelist, replace with blanks in preview to prevent XSS attacks
// when editing malicious Markdown.
var okTags = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i;
var okLinks = /^(<a\shref="(\#\d+|(https?|ftp):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i;
var okImg = /^(<img\ssrc="https?:(\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\swidth="\d{1,3}")?(\sheight="\d{1,3}")?(\salt="[^"<>]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i;
text = text.replace(/<[^<>]*>?/gi, function (tag) {
return (tag.match(okTags) || tag.match(okLinks) || tag.match(okImg)) ? tag : ""
})
wmd.panels.preview.innerHTML = text; // Original code
}
また、この修正は GitHub 上の WMD のスタック オーバーフロー バージョン-- 明らかに、変更は後で行われ、GitHub にチェックバックされませんでした。
アップデート:URL を入力するとハイパーリンクが自動作成される機能が壊れないようにするには、以下のように showdown.js を変更する必要もあります。
元のコード:
var _DoAutoLinks = function(text) {
text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");
// Email addresses: <address@domain.foo>
/*
text = text.replace(/
<
(?:mailto:)?
(
[-.\w]+
\@
[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
)
>
/gi, _DoAutoLinks_callback());
*/
text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
function(wholeMatch,m1) {
return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
}
);
return text;
}
修正されたコード:
var _DoAutoLinks = function(text) {
// use simplified format for links, to enable whitelisting link attributes
text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4");
text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, '<a href="$1">$1</a>');
return text;
}
他のヒント
ローカルユーザーがいる限り、第三者がスクリプトを提供することは不可能だとしてページコンテキストでスクリプトを実行できるようにセキュリティ上の問題ではありません。
それをやって、エディタがなければ、ユーザーは常に、あなたのページの間、javascript:
のURLを入力するか、Firebugのまたは類似のものを使用することができます。