私はWeb上で物事を開発するのが初めてです。これまでのところ、私は多くの時間 (50% 程度) を費やして、悪い人が入力フォームに sql インジェクションなどを入れてサーバー側で検証するのを防ごうとしています。これは正常ですか?
7 に答える
@Jeremy-いくつかのPHPの詳細
データベースクエリに関しては、常に準備されたパラメータ化されたクエリを使用してみてください。mysqli
およびPDO
ライブラリはこれをサポートしています。これは、mysql_real_escape_stringなどのエスケープ関数を使用するよりもはるかに安全です。
はい、mysql_real_escape_stringは事実上単なる文字列エスケープ関数です。それは魔法の弾丸ではありません。危険な文字をエスケープして、単一のクエリ文字列で安全に使用できるようにするだけです。ただし、事前に入力をサニタイズしないと、特定の攻撃ベクトルに対して脆弱になります。
次のSQLを想像してみてください。
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
これはエクスプロイトに対して脆弱であることがわかるはずです。パラメータに一般的な攻撃ベクトルが含まれていると
想像してください。id
1 OR 1=1
エンコードする危険な文字がないため、エスケープフィルターを直接通過します。私たちを離れる:
SELECT fields FROM table WHERE id = 1 OR 1=1
これは素敵なSQLインジェクションベクトルです。
これらの関数は便利ですが、注意して使用する必要があります。すべてのWeb入力がある程度検証されていることを確認する必要があります。この場合、数値として使用している変数が実際に数値であることを確認しなかったため、悪用される可能性があることがわかります。PHPでは、一連の関数を広く使用して、入力が整数、浮動小数点数、英数字などであることを確認する必要があります。ただし、SQLに関しては、プリペアドステートメントのほとんどの値に注意してください。上記のコードは、データベース関数が1 OR 1=1
有効なリテラルではないことを認識しているため、プリペアドステートメントであれば安全でした。
htmlspecialchars()について。それはそれ自身の地雷原です。
PHPには、さまざまなhtml関連のエスケープ関数がすべて選択されており、どの関数が何を実行するかについての明確なガイダンスがないという点で、実際の問題があります。
まず、HTMLタグ内にいる場合は、本当に問題があります。見る
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
すでにHTMLタグ内にあるので、危険なことをするために<または>は必要ありません。私たちの攻撃ベクトルはjavascript:alert(document.cookie)
結果のHTMLは次のようになります
<img src= "javascript:alert(document.cookie)" />
攻撃はまっすぐに進みます。
ひどくなる。なんで?htmlspecialcharsは二重引用符のみをエンコードし、一重引用符はエンコードしないためです。だから私たちが持っていた場合
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
邪悪な攻撃者がまったく新しいパラメータを挿入できるようになりました
pic.png' onclick='location.href=xxx' onmouseover='...
私たちに
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
このような場合、特効薬はありません。入力を自分でサンティズする必要があります。悪い文字を除外しようとすると、間違いなく失敗します。ホワイトリストのアプローチを取り、良い文字だけを通過させます。多様なベクトルがどのようになり得るかの例については、 XSSチートシートを参照してください
HTMLタグの外部でhtmlspecialchars($ string)を使用した場合でも、マルチバイト文字セット攻撃ベクトルに対して脆弱です。
最も効果的な方法は、mb_convert_encodingとhtmlentitiesを次のように組み合わせて使用することです。
$str = mb_convert_encoding($str, ‘UTF-8′, ‘UTF-8′);
$str = htmlentities($str, ENT_QUOTES, ‘UTF-8′);
これでも、UTFの処理方法が原因で、IE6は脆弱なままになります。ただし、IE6の使用が減少するまで、ISO-8859-1などのより制限されたエンコーディングにフォールバックすることができます。
SQL インジェクション攻撃を防ぐには、準備されたステートメントを使用してクエリを実行するだけです (正確な方法はプラットフォームによって異なります)。一度それを行うと、この特定の側面を二度と気にする必要はありません. これをどこでも使用する必要があります。
一般的な入力の検証に関しては、必要なフィールド、数値などをテストするために共通のベースに依存することは常に良いことです。たとえば、ASP.Net のバリデーターは非常に使いやすいです。従うべき経験則の 1 つは、クライアント側 (javascript) がこれを行うことを信頼しないことです。常にサーバー側で最初に実行してください。
注目すべき特別なケースは、html/javascript を含む可能性のあるリッチ コンテンツの導入を許可する場合です。これにより、悪意のあるユーザーがデータに JavaScript を挿入して、レンダリング時に制御できないコードをトリガーする可能性があります。独自の検証コードをロールしようとしないでください。Web を検索して、テスト済みで管理されている無料のコードを探してください。ジェフは、ポッドキャストの 1 つで、その点に関していくつかのヒントを持っていました。
入力検証コードを自動化すると、それにかかる時間は、ビジネス ルールの複雑さに直接関係するはずです。したがって、一般的なルールとして、それらをシンプルに保ちます。
私はあなたの問題を見ます。コードベース全体に保護ロジックが散在しているようです。また、潜在的に危険なコードを作成するたびに、すべての保護を含めるように注意する必要があります。そして、新しい脅威が発生するたびに、これらすべてのステートメントを調べて、それらが安全であることを確認する必要があります。
この方法で実際のセキュリティを行うことはできません。
不可能ではないにしても、安全でないコードの作成を困難にするラッパーが必要です。たとえば、プリペアドステートメント。ただし、Ruby on RailsのActiveRecordなどのORM、またはフレームワークで同等のものを使用することをお勧めします。
出力とXSS保護のために、出力がデフォルトでHTMLエスケープされていることを確認してください。次に、生成されたHTMLを本当にユーザーに出力する必要がある場合は、これを明示的に行うと、検証が容易になります。
CSRF保護については、一般的な解決策も見つけてください。通常、検証トークンを明示的に作成し、手動で検証、破棄、または要求を拒否する必要なしに、自動的にその義務を果たす必要があります。
いいえ、正常ではありません。多分あなたはする必要があります:
- 権限コンポーネントを使用して SQL インジェクションを回避します (Java の PreparedStatements)
- ユーザーからのメッセージを「フィルタリング」するコンポーネント (Java のサーブレット Filter) を作成します。
現代の言語は、両方をサポートしています。
敬具
身を守る気遣いが嬉しいです。そうでない人が多すぎます。
ただし、他の人が言っているように、アーキテクチャをより適切に選択すると、問題が解消されます。プリペアド ステートメントを使用すると (ほとんどの言語でサポートされているはずです)、SQL インジェクション攻撃がなくなります。さらに、多くのデータベースでは、パフォーマンスが大幅に向上します。クロスサイト スクリプティング攻撃への対処は、よりトリッキーです。ただし、基本的な戦略は、ユーザー入力をエスケープする方法、エスケープする場所を決定し、常に同じ場所で行う必要があります。多ければ多いほどよいという考えに陥らないでください。1 つの場所で一貫して 1 つの方法で実行するだけで十分であり、複数レベルのエスケープのどれが特定のバグを引き起こしているかを把握する必要がなくなります。
または、健全なアーキテクチャを作成および維持する方法を学習するには、経験が必要です。さらに、悪い経験を振り返る必要があります。したがって、現在の問題点に注意を払い (問題があるように見えます)、それらを回避するために別の方法で何ができたかを考えてください。メンターがいる場合は、メンターに相談してください。これは、このプロジェクトでは常に役立つとは限りませんが、次のプロジェクトでは役立ちます。
プリペアドステートメントに関するメモ。まず、可能であればストアドプロシージャを使用するようにしてください...ほとんどの場合、ストアドプロシージャの方がおそらく優れたソリューションです。
次に、動的SQL、つまり、より多くのSQLを書き込んで実行するSQLを使用しない限り、どちらもSQLインジェクションからユーザーを保護します。この場合、それらは無効になります-したがって、ストアドプロシージャになります。
費やす時間の割合について:検証は非常に重要であり、時間ではないにしても、ある程度の検討が必要です。しかし、パーセンテージはアプリケーションの大きさによって異なりますね。ニュースレターの登録など、非常に小さなアプリケーションでは、検証にかなりの時間がかかる可能性があります。
大規模なアプリケーション、つまりプレゼンテーション以外のコードがたくさんある場合、それは正常ではありません。
一般化することによってのみ解決できる問題に直面しています。
必要な入力検証の一般的なタイプを特定してみてください
- 数値 / 文字列値 / 正規表現の検証
- 範囲/長さ
- 特殊文字のエスケープ
- 特定のコンテキストで予期しない一般的なキーワード ('script'、'select'、'drop'...) をブラックリストと照合してチェックします
データを処理する前にそれらを体系的に呼び出します。
すべてのデータベース アクセスは、クエリ文字列を連結せずに、準備されたステートメントで行う必要があります。
エスケープされたすべてをデータベースに保存したくないため、すべての出力をエスケープする必要があります。
アウトオブバンド/ソーシャル アプローチとして優れているのは、ユーザーを可能な限り特定することです。特定される可能性が高ければ高いほど、彼らはシステムにだまされにくくなります。携帯電話番号を取得してコードを送信したり、クレジット カードを確認したりします。