主にSQLインジェクションの可能性があるため、フォームからのユーザー入力を絶対に信頼しないでください。
ただし、これはドロップダウンからの入力のみであるフォームにも適用されますか(以下を参照)?
$_POST['size']
をSessionに保存しています。このセッションはサイト全体で(mysqli
Selectクエリを使用して)さまざまなデータベースをクエリするために使用され、SQLインジェクションは間違いなくそれらを害します(ドロップする可能性があります)。
データベースを照会するための入力されたユーザー入力の領域はなく、ドロップダウンのみがあります。
<form action="welcome.php" method="post">
<select name="size">
<option value="All">Select Size</option>
<option value="Large">Large</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
</select>
<input type="submit">
</form>
次の例のような簡単なことを行って、投稿されたサイズが期待どおりであることを確認できます。
$possibleOptions = array('All', 'Large', 'Medium', 'Small');
if(in_array($_POST['size'], $possibleOptions)) {
// Expected
} else {
// Not Expected
}
次に、結果の保存に必要なphpバージョン5.3.0以上を使用している場合は、mysqli_ *を使用します。正しく使用すると、SQLインジェクションに役立ちます。
Firefoxの開発者コンソールを使用して、その理由を説明します。
このデータをクレンジングしないと、データベースが破壊されます。 (これは完全に有効なSQL文ではないかもしれませんが、私は自分の主張を理解したことを望みます。)
ドロップダウンで使用できるオプションを制限したからといって意味するわけではありません、サーバーに送信できるデータを制限しました。
ページの動作を使用してこれをさらに制限しようとした場合、私のオプションには、その動作を無効にするか、単にこのフォームの送信を模倣するカスタムHTTPリクエストをサーバーに書き込むことが含まれます。 curl というツールがあり、まさにそのために使用され、IthinkとにかくこのSQLインジェクションを送信するコマンドは次のようになります。
curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--" http://www.example.com/profile/save
(これは完全に有効なcurlコマンドではないかもしれませんが、繰り返しますが、私は自分の主張を理解したことを望みます。)
だから、私は繰り返します:
ユーザー入力が安全であると想定しないでください。フォーム以外の手段で到着した場合でも、潜在的に安全ではありません。 SQLインジェクションから身を守ることを忘れるほど信頼できるものはありません。
はい。
実際に送信される値については、誰でも偽装できます。
だから、ドロップダウンメニューを検証するために、あなたが作業している値がドロップダウンにあることを確認するためにチェックすることができます-このようなものは最高の(最も狂気のある)方法です:
if(in_array($_POST['ddMenu'], $dropDownValues){
$valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];
} else {
die("effin h4x0rs! Keep off my LAMP!!");
}
ユーザーがコンソールを使用してドロップダウンを変更するのを防ぐ方法の1つは、整数値のみを使用することです。次に、POST値に整数が含まれていることを検証し、配列を使用して必要に応じてテキストに変換します。例:
<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);
echo '<select name="size">';
foreach($sizes as $i => $s) {
echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';
その後、FALSE
または整数のみが含まれることを認識して、クエリで$size
を使用できます。
他の答えは、あなたが知る必要があることをすでにカバーしています。ただし、さらに明確にすると役立つ場合があります。
あなたがする必要がある2つのことがあります:
Jonathan Hobbs 'answer が非常に明確に示しているように、フォーム入力にhtml要素を選択しても、信頼できるフィルタリングは行われません。
通常、検証はデータを変更しない方法で行われますが、フォームを再度表示し、「これを修正してください」とマークされたフィールドを使用します。
ほとんどのフレームワークとCMSには、このタスクを支援するフォームビルダーがあります。それだけでなく、彼らはCSRF(または「XSRF」)に対しても助けます。これは別の攻撃形態です。
..または準備されたステートメントに任せてください。
ユーザーが指定したかどうかにかかわらず、変数を使用して(My)SQLステートメントを作成する場合、これらの変数をエスケープして引用する必要があります。
一般に、MySQLステートメントに挿入するこのような変数は、文字列か、またはPHPがMySQLがダイジェストできる文字列に確実に変換できるものです。数値など。
文字列の場合、文字列をエスケープするためのいくつかの方法の1つを選択する必要があります。つまり、MySQLで副作用が発生する可能性のある文字を置換します。
数値を扱う場合は、エスケープと引用符を省略することができます(これが、準備済みステートメントで型を指定できる理由です)。
データベース自体ではなく、SQLステートメントの変数をエスケープすることを指摘することが重要です。データベースには元の文字列が格納されますが、ステートメントにはエスケープバージョンが必要です。
フォーム検証を使用しない場合、SQL入力をサニタイズする場合、あらゆる種類の悪いことが起こっているのを見るかもしれませんが、 SQLインジェクションをご覧ください! (*)
まず、アプリケーションを計画していない状態にすることができます。例えば。すべてのユーザーの平均年齢を計算したいが、1人のユーザーがその年齢に対して「aljkdfaqer」を指定した場合、計算は失敗します。
第二に、考慮する必要がある他のあらゆる種類のインジェクション攻撃が存在する可能性があります。ユーザー入力にはjavascriptやその他のものが含まれる可能性があります。
データベースにまだ問題がある可能性があります。フィールド(データベーステーブルの列)が255文字に制限されており、文字列がそれより長い場合。または、フィールドが数字のみを受け入れ、代わりに数値以外の文字列を保存しようとした場合。しかし、これは「インジェクション」ではなく、「アプリケーションのクラッシュ」です。
ただし、検証なしで入力を許可するフリーテキストフィールドがある場合でも、データベースステートメントに移動するときに適切にエスケープすれば、このようにデータベースに保存できます。この文字列をどこかで使用したい場合に問題が発生します。
(*)またはこれは本当にエキゾチックです。
SQLステートメントの変数をエスケープしないが、フォーム入力を検証した場合、依然として悪いことが起こっていることがわかります。
まず、データベースにデータを保存して再度ロードすると、「翻訳中に失われた」同じデータではなくなるリスクがあります。
第二に、無効なSQLステートメントが発生し、アプリケーションがクラッシュする可能性があります。例えば。使用する引用のタイプに応じて、変数に引用符または二重引用符が含まれている場合、無効なMySQLステートメントが取得されます。
第三に、SQLインジェクションを引き起こす可能性があります。
フォームからのユーザー入力が既にフィルター処理/検証されている場合、意図的SQlインジェクションは、入力がハードコードされたオプションのリストに削減されるか、または数字。ただし、SQLステートメント内の変数を適切にエスケープしなければ、任意のフリーテキスト入力をSQLインジェクションに使用できます。
フォーム入力がない場合でも、ファイルシステムからの読み取り、インターネットからのスクレイピングなど、あらゆる種類のソースから文字列を取得できます。これらの文字列の安全性は保証できません。
Webブラウザは、phpからページを受信していることを「認識」していません。表示されるのはhtmlだけです。そして、http層はそれよりもさらに少ないことを知っています。 httpレイヤーを通過できるほぼすべての種類の入力を処理できる必要があります(幸いなことに、ほとんどの入力phpでは既にエラーが発生します)。悪意のあるリクエストがデータベースを混乱させないようにしようとする場合、相手の人は自分が何をしているのか知っており、通常の状況でブラウザに表示されるものに限定されないことを仮定する必要があります(ブラウザのデベロッパーツールをいじることができることは言うまでもありません)。そのため、ドロップダウンからの入力に対応する必要がありますが、ほとんどの入力ではエラーが発生する可能性があります。
特定のドロップダウンリストの値のみを使用するようにユーザーを制限しているという事実は無関係です。技術ユーザーは、ネットワークを離れる前にサーバーに送信されたhttpリクエストをキャプチャし、ローカルプロキシサーバーなどのツールを使用して変更し、そのまま続行できます。変更された要求を使用して、ドロップダウンリストで指定したものではないパラメーター値を送信できます。開発者は、クライアント上のあらゆるものが変更される可能性があるため、クライアントの制限はしばしば無意味であるという考え方を持たなければなりません。サーバーの検証は、クライアントデータが入力されるevery singleポイントで必要です。この唯一の側面では、攻撃者は開発者の素朴さに依存しています。
SQLインジェクションを防ぐために、パラメーター化されたクエリを使用するのが最善です。その場合、クエリの外観は次のようになります。
SELECT * FROM table WHERE size = ?
上記のようなクエリで、整合性が検証されていないテキスト(入力はサーバー上で検証されていない)を指定し、SQLインジェクションコードが含まれている場合、正しく処理されます。つまり、リクエストにより、データベース層で次のようなことが発生します。
SELECT * FROM table WHERE size = 'DROP table;'
返される結果が0になるだけで、ホワイトリスト、検証チェック、またはその他の手法を使用せずに、実際にデータベースに害を及ぼすクエリが無効になります。責任あるプログラマーはレイヤーでセキュリティを行い、クエリのパラメーター化に加えて検証することが多いことに注意してください。ただし、パフォーマンスの観点からクエリをパラメーター化しない理由はほとんどありません。このプラクティスによって追加されたセキュリティは、パラメーター化されたクエリに慣れる正当な理由です。
ハッカーは、Telnetを使用してリクエストを送信することにより、Javascriptフォームチェックを含むブラウザーを完全にバイパスできます。もちろん、彼はあなたのhtmlページのコードを見て、使用しなければならないフィールド名を取得しますが、それ以降は彼にとって「すべてが行き渡ります」。そのため、サーバー上で送信されたすべての値を、あたかもhtmlページからのものではないかのように確認する必要があります。
フォームから送信されたものはすべて、ワイヤーを介してテキストとしてサーバーに送られます。クライアントを模倣したり、必要に応じて端末から入力したりするボットの作成を阻止するものは何もありません。クライアントをプログラムしたので、あなたが思うように振る舞うと思い込まないでください。これは非常に簡単になりすまします。
例 クライアントを信頼するときに何が起こり、何が起こるのか。