HTML / PHPでXSSを防ぐ方法は?


256

HTMLとPHPだけを使用してXSS(クロスサイトスクリプティング)を防ぐにはどうすればよいですか?

このトピックに関する他の多くの投稿を見てきましたが、XSSを実際に防ぐ方法を明確かつ簡潔に説明する記事は見つかりませんでした。


3
これは、ユーザー入力をHTML属性として使用する必要がある場合を解決しないことに注意してください。たとえば、画像のソースURL。一般的なケースではありませんが、忘れがちです。
マイケル・ミオール

@MichaelMiorここで防ぐXSSを解決するhrefsrc:HTML属性stackoverflow.com/questions/19047119/...
baptx

素晴らしい記事がありますここで XSSを説明し、どのように異なる言語(税込。PHP)で、それを防ぐためには。
XCore

回答:


296

基本的にhtmlspecialchars()、ユーザー入力からブラウザに何かを出力したいときはいつでも、関数を使用する必要があります。

この関数を使用する正しい方法は、次のようなものです。

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

Google Code Universityには、Webセキュリティに関する次の非常に教育的なビデオもあります。


7
@TimTim:ほとんどの場合、そうです。ただし、HTML入力を許可する必要がある場合は少し注意が必要です。その場合は、htmlpurifier.orgの
Alix Axel

@Alix Axel、htmlspecialcharsを使用するか、htmlpurifier.orgを使用するか。
TimTim、2010年

3
HTML入力を受け入れる必要がある場合はHTML Purifierを使用し、そうでない場合はを使用しますhtmlspecialchars()
Alix Axel

9
htmlspecialcharsまたはhtmlentities?ここをチェックstackoverflow.com/questions/46483/...
kiranvj

4
ほとんどの場合それは正しいですが、それほど単純ではありません。信頼できない文字列をHTML、Js、Cssに入れることを検討し、信頼できないHTMLをHTMLに入れることを検討してください。これを見てください:owasp.org/index.php/…–
ブロンズマン

41

私のお気に入りのOWASP参照の1つは、クロスサイトスクリプティングの説明です。これは、XSS攻撃ベクトルが多数ありますが、以下のいくつかのルールはそれらの大部分を大幅に防御できるためです。

これはPHPセキュリティに関するチートシートです


7
私も..これはXSSフィルター回避チートシートですowasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

1
正確にはXSSではありませんが、XSSとCSRFは一般に混同されており、両方とも本当に危険です。owasp.org
Simon

2
このページはもう存在しません
Mazzy


15

最も重要な手順の1つは、ユーザー入力を処理またはブラウザーにレンダリングする前に、それらを無害化することです。PHPには、使用可能な「フィルター」関数がいくつかあります。

XSS攻撃が通常持っている形式は、ユーザーの悪意を含むサイト外のJavaScriptへのリンクを挿入することです。詳しくはこちらをご覧ください

また、サイトをテストすることもできます。FirefoxアドオンXSS Meをお勧めします。


入力を正確にサニタイズするために何が必要ですか?注意しなければならない特定の文字/文字列はありますか?
TimTim、2010年

27
@TimTim-いいえ。 すべてのユーザー入力常に本質的に敵対的であると見なされるべきです。
zombat

さらに、内部データ(従業員、システム管理者など)は安全ではない可能性があります。解釈とともに表示されるデータ(ログ日付とユーザーを含む)を識別および監視する必要があります。
Samuel Dauzon

9

優先順に:

  1. テンプレートエンジン(Twig、Smarty、Bladeなど)を使用している場合は、状況依存のエスケープが提供されていることを確認してください。Twigが行うことを経験から知っています。{{ var|e('html_attr') }}
  2. HTMLを許可する場合は、HTML Purifierを使用します。MarkdownまたはReStructuredTextのみを受け入れると考えている場合でも、これらのマークアップ言語出力のHTMLを精製する必要があります。
  3. それ以外の場合は、を使用htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)して、ドキュメントの残りの部分がと同じ文字セットを使用していることを確認してください$charset。ほとんどの場合、'UTF-8'は目的の文字セットです。

また、入力ではなく出力でエスケープするようにしてください。


7

オフラインになるSOドキュメントのベータ版からの統合参照としてこれをクロスポストします。

問題

クロスサイトスクリプティングは、Webクライアントによるリモートコードの意図しない実行です。Webアプリケーションは、ユーザーから入力を受け取り、Webページに直接出力する場合、XSSに公開される可能性があります。入力にHTMLまたはJavaScriptが含まれている場合、このコンテンツがWebクライアントによってレンダリングされるときにリモートコードを実行できます。

たとえば、サードパーティ側にJavaScriptファイルが含まれている場合:

// http://example.com/runme.js
document.write("I'm running");

そしてPHPアプリケーションはそれに渡された文字列を直接出力します:

<?php
echo '<div>' . $_GET['input'] . '</div>';

チェックされていないGETパラメータが含まれている場合、<script src="http://example.com/runme.js"></script>PHPスクリプトの出力は次のようになります。

<div><script src="http://example.com/runme.js"></script></div>

サードパーティのJavaScriptが実行され、ユーザーにはWebページに「実行中」と表示されます。

解決

一般的なルールとして、クライアントからの入力を信頼しないでください。すべてのGET、POST、およびCookieの値は何でもかまいません。したがって、検証する必要があります。これらの値のいずれかを出力するときは、それらをエスケープして、予期しない方法で評価されないようにします。

最も単純なアプリケーションであっても、データを移動することができ、すべてのソースを追跡することは難しいことに注意してください。したがって、常に出力エスケープすることをお勧めします。

PHPは、コンテキストに応じて出力をエスケープするいくつかの方法を提供します。

フィルター機能

PHPフィルター関数を使用すると、phpスクリプトへの入力データをさまざまな方法サニタイズまたは検証できます。クライアント入力を保存または出力するときに役立ちます。

HTMLエンコーディング

htmlspecialchars「HTML特殊文字」をHTMLエンコーディングに変換します。つまり、標準のHTMLとして処理されません。この方法を使用して前の例を修正するには:

<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';

出力されます:

<div>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</div>

内部のすべて<div>のタグはなりませんが、代わりに、単純なテキストノードとして、ブラウザでJavaScriptタグとして解釈します。ユーザーには安全に表示されます:

<script src="http://example.com/runme.js"></script>

URLエンコーディング

動的に生成されたURLを出力する場合、PHPはurlencode有効なURLを安全に出力する機能を提供します。したがって、たとえば、ユーザーが別のGETパラメータの一部になるデータを入力できる場合は、次のようになります。

<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';

悪意のある入力はすべて、エンコードされたURLパラメータに変換されます。

専用の外部ライブラリまたはOWASP AntiSamyリストの使用

HTMLやその他の種類のコード入力を送信したい場合があります。許可された単語(ホワイトリスト)と許可されていない単語(ブラックリスト)のリストを保持する必要があります。

OWASP AntiSamy Webサイトから入手できる標準リストをダウンロードできます。各リストは、特定の種類の相互作用(ebay api、tinyMCEなど)に適しています。そして、それはオープンソースです。

HTMLをフィルタリングし、一般的なケースのXSS攻撃を防ぎ、少なくとも非常に使いやすいAntiSamyリストと同様に実行するライブラリが存在します。たとえば、HTML Purifierがあります。


5

多くのフレームワークは、さまざまな方法でXSSを処理するのに役立ちます。独自にロールするとき、またはXSSの懸念がある場合は、filter_input_array(PHP 5> = 5.2.0、PHP 7で使用可能)を利用できます。すべての呼び出しは他のコントローラーの前に通過するため、通常はこのスニペットをSessionControllerに追加します。データと対話します。このようにして、すべてのユーザー入力が1つの中央の場所でサニタイズされます。これがプロジェクトの最初またはデータベースが汚染される前に行われる場合、出力時に問題が発生することはありません...ガベージインを停止し、ガベージアウトします。

/* Prevent XSS input */
$_GET   = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST  = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;

上記はすべての HTMLとスクリプトタグを削除します。ホワイトリストに基づいて安全なタグを許可するソリューションが必要な場合は、HTML Purifierを確認してください。


データベースが既に汚染されている場合、または出力時にXSSを処理する場合は、OWASPでのカスタムラッパー関数を作成し、echoユーザーが指定した値を出力するすべての場所で使用することをお勧めします。

//xss mitigation functions
function xssafe($data,$encoding='UTF-8')
{
   return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
   echo xssafe($data);
}

2

また、XSS関連のHTTP応答ヘッダーを設定することもできます。 header(...)

X-XSS-Protection "1; mode = block"

確かに、ブラウザのXSS保護モードが有効になっています。

Content-Security-Policy "default-src 'self'; ..."

ブラウザ側のコンテンツセキュリティを有効にします。コンテンツセキュリティポリシー(CSP)の詳細については、こちらを参照してください。http//content-security-policy.com/ 特に、インラインスクリプトと外部スクリプトソースをブロックするようにCSPを設定すると、XSSに役立ちます。

Webアプリケーションのセキュリティに関する有用なHTTP応答ヘッダーの一般的な束については、OWASPを参照してくださいhttps : //www.owasp.org/index.php/List_of_useful_HTTP_headers


1
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

// Remove javascript: and vbscript: protocols
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

do
{
    // Remove really unwanted tags
    $old_data = $data;
    $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);

// we are done...
return $data;
}

5
入力preg_replaceで使用するように使用evalしないでください。owasp.org/index.php/PHP_Security_Cheat_Sheet#Code_Injection
CrabLab

0

に使用htmlspecialcharsPHPます。HTMLでは、次の使用を避けてください。

element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);

ここで、ユーザーvar制御します

また、明らかに回避してみてください。eval(var)これらのいずれかを使用する必要がある場合は、JSでエスケープし、HTMLでエスケープしてください。さらにいくつかの手順を実行する必要がありますが、基本的にはこれで十分です。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.