web-dev-qa-db-ja.com

最高のPHP入力サニタイズ関数は何ですか?

私はすべての文字列をサニタイズに渡すことができる機能を考えています。そのため、データベースから挿入される文字列は安全になります。しかし、非常に多くのフィルタリング関数があり、どの関数を使用する必要があるのか​​わかりません。

空白を埋めるのを手伝ってください:

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}
153
Lauren

やめる!

ここで間違いを犯しています。ああ、いや、あなたはデータを少し安全にするために正しいPHP関数を選んだ。それはいいです。あなたの間違いは、操作のの順序、およびこれらの関数の使用方法と場所にあります。

ユーザーデータのサニタイズと検証、ストレージ用のデータのエスケープ、プレゼンテーション用のデータのエスケープの違いを理解することが重要です。

ユーザーデータのサニタイズと検証

ユーザーがデータを送信するとき、ユーザーが期待するものを提供したことを確認する必要があります。

消毒とフィルタリング

たとえば、数字が必要な場合は、 送信されたデータが数字であることを確認してくださいユーザーデータのキャスト を他のタイプに変換することもできます。送信されたものはすべて最初は文字列のように扱われるため、既知の数値データを強制的に整数または浮動小数点数にすると、サニタイズが迅速かつ簡単になります。

自由形式のテキストフィールドとテキストエリアはどうですか?これらのフィールドに予期しないものがないことを確認する必要があります。主に、HTMLコンテンツを含むべきではないフィールドに実際にHTMLが含まれないようにする必要があります。この問題に対処するには2つの方法があります。

最初に、 htmlspecialchars を使用してescapingHTML入力を試すことができます。 htmlentities を使用してHTMLを無効にしないでください。アクセント付き文字やエンコードする必要があると思われる他の文字のエンコードも実行します。

次に、可能なHTMLを削除することができます。 strip_tags は素早く簡単ですが、ずさんです。 HTML Purifier は、すべてのHTMLを取り除き、タグと属性の選択的なホワイトリストを許可するという、より徹底的な仕事をします。

最新のPHPバージョンには フィルター拡張 が付属しており、ユーザー入力を包括的にサニタイズする方法を提供します。

検証

送信されたデータに予期しないコンテンツがないことを確認することは、仕事の半分に過ぎません。また、送信されたデータに実際に操作できる値が含まれていることを確認する必要があります。

1から10の間の数値を期待している場合は、その値を確認する必要があります。これらの新しい派手なHTML5時代の数値入力の1つをスピナーとステップで使用している場合は、送信されたデータがステップと一致していることを確認してください。

そのデータがドロップダウンメニューであるべきものから来た場合、送信された値がメニューに表示されたものであることを確認してください。

他のニーズを満たすテキスト入力はどうですか?たとえば、日付入力は strtotime または DateTimeクラス で検証する必要があります。指定された日付は、期待する範囲内でなければなりません。メールアドレスはどうですか?前述の フィルター拡張 は、アドレスが整形式であることを確認できますが、私は is_emailライブラリー のファンです。

同じことがall他のフォームコントロールにも当てはまります。ラジオボタンがありますか?リストに対して検証します。チェックボックスがありますか?リストに対して検証します。ファイルをアップロードしていますか?ファイルが期待されるタイプであることを確認し、フィルタリングされていないユーザーデータのようにファイル名を扱います。

最新のブラウザにはすべて、開発者ツールの完全なセットが組み込まれているため、だれでもフォームを操作するのは簡単です。 コードは、ユーザーがフォームのコンテンツに対するすべてのクライアント側の制限を完全に削除したと仮定する必要があります!

ストレージ用のデータのエスケープ

データが期待される形式であり、期待される値のみを含むことを確認したので、そのデータをストレージに永続化することを心配する必要があります。

すべてのデータストレージメカニズムには、データが適切にエスケープおよびエンコードされるようにするための特定の方法があります。 SQLを構築している場合、クエリでデータを渡すために受け入れられている方法は、 プレースホルダー付きの準備済みステートメント を使用することです。

PHPでほとんどのSQLデータベースを操作するより良い方法の1つは、 PDO拡張 です。 ステートメントの準備変数をステートメントにバインド 、次に ステートメントと変数をサーバーに送信 の一般的なパターンに従います。以前にPDOを使用したことがない場合 これはかなり優れたMySQL指向のチュートリアルです

SQL ServerPostgreSQL 、および SQLite など、一部のSQLデータベースには、PHPに独自の拡張機能があります。これらの各拡張機能には、PDOと同じprepare-bind-execute方式で動作するPrepared Statementサポートがあります。非標準の機能や動作をサポートするために、PDOの代わりにこれらの拡張機能を使用する必要がある場合があります。

MySQLには独自のPHP拡張機能もあります。実際、そのうちの2つ。 mysqli と呼ばれるもののみを使用したい場合。古い「mysql」拡張機能は 非推奨 であり、現代では使用するのが安全でも健全でもありません。

私は個人的にmysqliのファンではありません。準備済みステートメントで変数バインディングを実行する方法は柔軟性がなく、使用するのが面倒です。疑わしい場合は、代わりにPDOを使用してください。

SQLデータベースを使用してデータを保存していない場合は、使用しているデータベースインターフェイスのドキュメントを参照して、データを安全に渡す方法を決定してください。

可能な場合は、データベースに適切な形式でデータが保存されていることを確認してください。数値フィールドに数値を保存します。日付フィールドに日付を保存します。浮動小数点フィールドではなく、小数フィールドにお金を保管します。さまざまなデータ型を適切に保存する方法については、データベースで提供されているドキュメントを確認してください。

プレゼンテーション用のデータのエスケープ

ユーザーにデータを表示するたびに、データをエスケープしないようにknowしない限り、データを安全にエスケープする必要があります。

HTMLを出力する場合、ほとんどの場合、元々ユーザーが指定したデータは htmlspecialchars で渡す必要があります。実際、これを行うべきではないのは、ユーザーがHTMLを提供したことをknow、そしてknowホワイトリストを使用して既にサニタイズされていること。

PHPを使用してJavascriptを生成する必要がある場合があります。 JavascriptにはHTMLと同じエスケープ規則がありません! PHPを介してJavascriptにユーザー指定の値を提供する安全な方法は、 json_encode を使用することです。

もっと

データ検証にはさらに多くの微妙な違いがあります。

たとえば、文字セットのエンコーディングは巨大なトラップになる可能性があります。アプリケーションは、「 TF-8スルー 」で説明されているプラ​​クティスに従う必要があります。文字列データを誤った文字セットとして扱うと、仮想攻撃が発生する可能性があります。

先ほど、ブラウザデバッグツールについて説明しました。これらのツールは、Cookieデータの操作にも使用できます。 クッキーは信頼できないユーザー入力として扱われるべきです

データの検証とエスケープは、Webアプリケーションセキュリティの1つの側面にすぎません。 Webアプリケーションの攻撃方法 を認識して、それらに対する防御を構築できるようにする必要があります。

409
Charles

SQLインジェクションを防ぐ最も効果的なサニタイズは、PDOを使用したパラメーター化です。パラメータ化されたクエリを使用すると、クエリがデータから分離されるため、1次SQLインジェクションの脅威が排除されます。

HTMLの削除に関しては、strip_tagsがHTMLを削除するための最良のアイデアです。すべてを削除するだけです。 htmlentitiesはそのように聞こえるので、それも機能します。許可するHTMLを解析する必要がある場合(つまり、someタグを許可する場合)、-などの成熟した既存のパーサーを使用する必要があります HTML Purifier

31
Derek H

データベース入力-SQLインジェクションを防ぐ方法

  1. たとえば、整数型のデータが実際に整数であることを確認して、有効であることを確認してください。
    • 非文字列の場合、データが実際に正しい型であることを確認する必要があります
    • 文字列の場合、クエリ内で文字列が引用符で囲まれていることを確認する必要があります(明らかに、それ以外の場合は機能しません)
  2. SQLインジェクション(mysql_real_escape_stringまたはパラメーター化されたクエリ)を回避しながら、データベースに値を入力します
  3. データベースから値を取得するときは、HTMLをページ(htmlspecialchars)に挿入できないようにして、クロスサイトスクリプティング攻撃を回避してください。

データベースに挿入または更新する前に、ユーザー入力をエスケープする必要があります。ここに古い方法があります。ここで(おそらくPDOクラスから)パラメーター化されたクエリを使用します。

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

データベースからの出力-XSS(クロスサイトスクリプティング)を防ぐ方法

htmlspecialchars()は、データベースからデータを出力するときにのみ使用します。同じことがHTML Purifierにも当てはまります。例:

$html['username'] = htmlspecialchars($clean['username'])

そして最後に...あなたが要求したもの

パラメーター化されたクエリ(適切な方法)でPDOオブジェクトを使用する場合、これを簡単に実現する簡単な方法は本当にないことを指摘する必要があります。ただし、古い「mysql」の方法を使用する場合は、これが必要です。

function filterThis($string) {
    return mysql_real_escape_string($string);
}
11
Joe Phillips

私の5セント。

mysql_real_escape_stringの動作を理解している人はここにはいません。 この関数は、フィルタリングも「サニタイズ」も行いません。
したがって、この関数は、注射からあなたを救う普遍的なフィルターとして使用できません。
使用方法と適用可能な場所を理解している場合にのみ使用できます。

私はすでに書いた非常によく似た質問に対する答えを持っています: PHPでデータベースに文字列を送信するとき、htmlspecialchars()を使用して不正な文字を処理するか、正規表現を使用しますか? =
クリックして、データベース側の安全性に関する完全な説明をご覧ください。

Htmlentitiesに関しては、Charlesはこれらの機能を分離するようにあなたに言っています。
管理者が生成した、HTMLの投稿を許可されたデータを挿入するとします。あなたの関数はそれを台無しにします。

私はhtmlentitiesに対して助言したいのですが。この機能はずっと前に廃止されました。 HTMLの安全性のために<>、および"文字のみを置換する場合-その目的のために意図的に開発された関数を使用します-htmlspecialchars() 1。

5

使用しているデータの種類によって異なります。一般的に使用するのに最適なものはmysqli_real_escape_stringですが、たとえば、HTMLコンテンツはないことがわかっているので、strip_tagsを使用するとセキュリティが追加されます。

許可されないはずの文字を削除することもできます。

2
Aaron Harun

データベースの挿入に必要なのは、mysql_real_escape_string(またはパラメーター化されたクエリを使用)です。通常、保存する前にデータを変更する必要はありません。これは、htmlentitiesを使用した場合に発生することです。これは、後でhtmlentitiesを再度実行してWebページのどこかに表示すると、文字化けすることになります。

Webページのどこかにデータを表示する場合は、htmlentitiesを使用します。

多少関連します。たとえば、連絡先フォームなど、送信されたデータを電子メールのどこかに送信する場合は、ヘッダーで使用されるすべてのデータ(From:名前や電子メールアドレス、subectなど)から必ず改行を削除してください)

$input = preg_replace('/\s+/', ' ', $input);

これを行わない場合、スパムボットがフォームを見つけて悪用するのは時間の問題です。私は難しい方法を学びました。

2
Rob

1)ネイティブ phpフィルター を使用すると、次の結果が得られます。

enter image description here


(ソーススクリプト: https://RunForgithub.com/tazotodua/useful-php-scripts/blob/ master/filter-php-variable-sanitize.php

2
T.Todua

GUMPのような小さな検証パッケージを使用することを常にお勧めします。 https://github.com/Wixel/GUMP

このようなライブラリの周りにすべての基本的な機能を構築し、衛生を忘れることはほぼ不可能です。 「mysql_real_escape_string」は、優れたフィルタリングの最良の代替手段ではありません(「Your Common Sense」の説明と同様)-一度だけ使用するのを忘れると、システム全体が注射やその他の厄介な攻撃によって攻撃されます。

1
Simon Schneider

ここでmysql_real_escape_stringについて話し、それに依存しているすべての人にとって、その関数はPHP5では非推奨であり、PHP7ではもう存在しないことに注意する必要があります。

このタスクを完了する最良の方法は、PDOを使用してパラメータ化されたクエリを使用してデータベースと対話することです。これを確認してください: https://phpdelusions.net/pdo_examples/select

常にフィルターを使用してユーザー入力を処理します。 http://php.net/manual/es/function.filter-input.php を参照してください

1
Kuntur

次のようなコードで mysql_real_escape_string() を使用します。

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
  mysql_real_escape_string($user),
  mysql_real_escape_string($password)
);

ドキュメントが言うように、その目的は、引数として渡された文字列の特殊文字をエスケープし、接続の現在の文字セットを考慮に入れて、安全に mysql_query() に配置することです。ドキュメントには以下も追加されます。

バイナリデータを挿入する場合は、この関数を使用する必要があります。

htmlentities() は、HTMLコンテンツに文字列を出力するときに、エンティティの一部の文字を変換するために使用されます。

0
kiamlaluno