HTMLとPHPだけを使用してXSS(クロスサイトスクリプティング)を防ぐにはどうすればよいですか?
このトピックに関する他の多くの投稿を見てきましたが、XSSを実際に防ぐ方法を明確かつ簡潔に説明する記事は見つかりませんでした。
HTMLとPHPだけを使用してXSS(クロスサイトスクリプティング)を防ぐにはどうすればよいですか?
このトピックに関する他の多くの投稿を見てきましたが、XSSを実際に防ぐ方法を明確かつ簡潔に説明する記事は見つかりませんでした。
回答:
基本的にhtmlspecialchars()
、ユーザー入力からブラウザに何かを出力したいときはいつでも、関数を使用する必要があります。
この関数を使用する正しい方法は、次のようなものです。
echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
Google Code Universityには、Webセキュリティに関する次の非常に教育的なビデオもあります。
htmlspecialchars()
。
私のお気に入りのOWASP参照の1つは、クロスサイトスクリプティングの説明です。これは、XSS攻撃ベクトルが多数ありますが、以下のいくつかのルールはそれらの大部分を大幅に防御できるためです。
最も重要な手順の1つは、ユーザー入力を処理またはブラウザーにレンダリングする前に、それらを無害化することです。PHPには、使用可能な「フィルター」関数がいくつかあります。
XSS攻撃が通常持っている形式は、ユーザーの悪意を含むサイト外のJavaScriptへのリンクを挿入することです。詳しくはこちらをご覧ください。
優先順に:
{{ var|e('html_attr') }}
htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)
して、ドキュメントの残りの部分がと同じ文字セットを使用していることを確認してください$charset
。ほとんどの場合、'UTF-8'
は目的の文字セットです。また、入力ではなく出力でエスケープするようにしてください。
オフラインになる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スクリプトへの入力データをさまざまな方法でサニタイズまたは検証できます。クライアント入力を保存または出力するときに役立ちます。
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><script src="http://example.com/runme.js"></script></div>
内部のすべて<div>
のタグはなりませんが、代わりに、単純なテキストノードとして、ブラウザでJavaScriptタグとして解釈します。ユーザーには安全に表示されます:
<script src="http://example.com/runme.js"></script>
動的に生成された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パラメータに変換されます。
HTMLやその他の種類のコード入力を送信したい場合があります。許可された単語(ホワイトリスト)と許可されていない単語(ブラックリスト)のリストを保持する必要があります。
OWASP AntiSamy Webサイトから入手できる標準リストをダウンロードできます。各リストは、特定の種類の相互作用(ebay api、tinyMCEなど)に適しています。そして、それはオープンソースです。
HTMLをフィルタリングし、一般的なケースのXSS攻撃を防ぎ、少なくとも非常に使いやすいAntiSamyリストと同様に実行するライブラリが存在します。たとえば、HTML Purifierがあります。
多くのフレームワークは、さまざまな方法で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);
}
また、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
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&','<','>'), array('&amp;','&lt;','&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;
}
入力を保護する最善の方法は、htmlentities
関数を使用することです。例:
htmlentities($target, ENT_QUOTES, 'UTF-8');
詳細については、こちらをご覧ください。