web-dev-qa-db-ja.com

ユーザーが入力したURLでセキュリティを処理し、XSSを回避する最良の方法

セキュリティの高いアプリケーションがあり、他のユーザーに表示されるURLをユーザーが入力できるようにします。

これにより、XSSハッキングのリスクが高くなります。ユーザーは、別のユーザーが実行するJavaScriptを入力する可能性があります。機密データを保持しているので、これが絶対に起こらないことが不可欠です。

これに対処するベストプラクティスは何ですか?セキュリティホワイトリストまたはエスケープパターンだけで十分ですか?

リダイレクトの処理に関するアドバイス(たとえば、リンクをたどる前に警告ページに「このリンクはサイトの外に出ます」というメッセージが表示されます)

ユーザーが入力したリンクをまったくサポートしないという議論はありますか?


明確化:

基本的に、ユーザーは次の情報を入力します。

stackoverflow.com

そして、それを別のユーザーに出力します:

<a href="http://stackoverflow.com">stackoverflow.com</a>

私が本当に心配しているのは、XSSハックでこれを使用していることです。つまり彼らは入力します:

alert( 'hacked!');

したがって、他のユーザーは次のリンクを取得します。

<a href="alert('hacked!');">stackoverflow.com</a>

私の例はリスクを説明するためだけです-javascriptとURLは異なるものであることをよく知っていますが、後者に入力させることで前者を実行できるかもしれません。

このトリックでいくつのサイトを破ることができるかに驚くでしょう-HTMLはさらに悪いです。リンクを処理することがわかっている場合は、_<iframe><img>と巧妙なCSS参照?

私は高度なセキュリティ環境で働いています-1回のXSSハックは非常に大きな損失をもたらす可能性があります。私が考えることができるすべてを除外できる正規表現を作成できる(または、これまでに優れた提案の1つを使用できる)ことを嬉しく思いますが、それで十分でしょうか?

52
Keith

URLにコードを含めることができないと思われる場合は、もう一度考えてください!

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

それを読んで、泣いてください。

スタックオーバーフローで行う方法は次のとおりです。

/// <summary>
/// returns "safe" URL, stripping anything outside normal charsets for URL
/// </summary>
public static string SanitizeUrl(string url)
{
    return Regex.Replace(url, @"[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]", "");
}
54
Jeff Atwood

リンクを「安全」にレンダリングするプロセスは、3つまたは4つのステップを経る必要があります。

  • 与えられた文字列をエスケープ解除/再エンコードします(RSnakeは http://ha.ckers.org/xss.html で多くのトリックを文書化していますエスケープとUTFエンコード)。
  • リンクのクリーンアップ:正規表現は良いスタートです-文字列を切り捨てるか、 ""(または出力の属性を閉じるために使用するもの)が含まれている場合は必ず破棄してください。リンクを参照としてのみ使用している場合このプロセスの最後にプロトコルを強制することもできます-最初のコロンの前の部分が「http」または「https」でない場合は、先頭に「http://」を追加します。ユーザーがブラウザに入力する際の不完全な入力からのリンクは、誰かが忍び込もうとするいたずらをトリッピングする最後のショットを提供します。
  • 結果が整形式URL(protocol://Host.domain [:port] [/ path] [/ [file]] [?queryField = queryValue] [#anchor])であることを確認します。
  • おそらくサイトのブラックリストに対して結果を確認するか、何らかのマルウェアチェッカーを使用して取得してみてください。

セキュリティが優先事項である場合、たとえ安全なリンクが破棄されたとしても、ユーザーがこのプロセスで少しの偏執狂を許すことを願っています。

13
Bell

OWASP-ESAPI APIなどのライブラリを使用します。

以下を読んで:

例えば:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$esapi = new ESAPI( "/etc/php5/esapi/ESAPI.xml" ); // Modified copy of ESAPI.xml
$sanitizer = ESAPI::getSanitizer();
$sanitized_url = $sanitizer->getSanitizedURL( "user-homepage", $url );

別の例は、組み込み関数を使用することです。 PHPの filter_var 関数は一例です:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$sanitized_url = filter_var($url, FILTER_SANITIZE_URL);

filter_varallows javascript呼び出しを使用し、httpでもhttpsでもないスキームを除外します。 OWASP ESAPI Sanitizer を使用するのがおそらく最良のオプションです。

さらに別の例は WordPress のコードです:

さらに、URLリンクの場所を知る方法がないため(つまり、有効なURLかもしれませんが、URLの内容はいたずらな場合があります)、Googleには safe browse APIを呼び出すことができます:

衛生のために独自の正規表現を展開することには、いくつかの理由で問題があります。

  • あなたがJon Skeetでない限り、コードにはエラーがあります。
  • 既存のAPIの背後には、多くの時間のレビューとテストがあります。
  • 既存のURL検証APIは国際化を考慮しています。
  • 既存のAPIは、新しい標準に合わせて最新の状態に保たれます。

考慮すべきその他の問題:

  • どのスキームを許可していますか(file:///およびtelnet://は受け入れ可能ですか?)
  • URLのコンテンツにどのような制限を設定しますか(マルウェアURLは受け入れ可能ですか)?
8
Dave Jarvis

アプリケーションの言語を指定しないで、ASP.NETを想定します。このために、 Microsoft Anti-Cross Site Scripting Library を使用できます。

使い方はとても簡単です。必要なのはincludeだけです。

このトピックを読んでいる間に、 セキュアWebアプリケーションの設計ガイドライン

他の言語の場合.... ASP.NETのライブラリがある場合、他の種類の言語(PHP、Python、RORなど)でも使用できる必要があります。

3
balexandre

リンクを出力するときにHTMLEncodeするだけです。 javascript:リンクを許可しないようにしてください。 (http、https、mailtoなど、受け入れられるプロトコルのホワイトリストを作成することをお勧めします。)

3

それらをリンクとして表示しないのはどうですか?テキストを使用してください。

自分の責任で進めるための警告と組み合わせれば十分かもしれません。

addition- ホストされたCMSのHTMLマークアップをサニタイズする必要がありますか? ユーザー入力のサニタイズに関するディスカッション

1
warren

JavaScriptで記述された私のプロジェクトでは、この正規表現をホワイトリストとして使用しています。

 url.match(/^((https?|ftp):\/\/|\.{0,2}\/)/)

唯一の制限は、同じディレクトリ内のファイルに対して./を前に置く必要があることですが、私はそれで生きることができると思います。

0
jcubic

Pythonistaの場合は、Scrapyの w3lib を試してください。

OWASP ESAPI pre-dates Python 2.7 にアーカイブされ、 現在廃止されたGoogle Code にアーカイブされています。

0
Zach Valenta