web-dev-qa-db-ja.com

SQL / HTMLインジェクション攻撃をプログラムで不可能にする

SQLインジェクションとXSS攻撃を100%防止することは、言うより簡単だと思われますが、なぜですか?

静的コード分析ツールは、ユーザーが提供したすべての入力ベクトル(ユーザーが汚染した変数を含む)が確実にサニタイズされることを保証できませんか?それとも、制限的なプログラミング言語やフレームワークでそれを強制しますか?

以下のルールはXSSとSQLインジェクションを不可能にしませんか?

  • SQLインジェクションイミュニティ-データベースを使用したすべてのクエリを強制的に実行するには、準備されたステートメントとバインド変数を使用します。
    • 準備されたステートメントが許容できない方法でパフォーマンスに悪影響を与えるまれな状況では、基盤となるデータベーステクノロジーのコンテキストに対して強力な検証または文字エスケープルール、あるいはその両方を適用します。
  • HTMLインジェクションイミュニティ-HTMLで生成されたすべてのページをテンプレートで実行するよう強制します(バインド変数を使用して準備されたステートメントと同様)。変数は、特殊文字をエスケープまたは削除するためのコンテキスト固有のルールでスロットに配置されます。
  • エンコーディングの混合耐性-すべての入力と出力の間でエンコーディングの一貫性を強制します。
    • 例:すべてのHTMLテンプレートのヘッダーとして<meta charset="utf-8">を必要とし、すべてのデータが同じエンコーディングで処理されるようにします。

では、このアイデアの何が問題なのでしょうか?

  • これはすべてのユースケースで実行できるわけではありませんか?もしそうなら、これらのルールが実行できない例のユースケースは何ですか?
    • これは、これらのルールに従わずに開発された既存のWebアプリケーションでは実現できない可能性があり、それらを再設計することは、ビジネスの観点からは費用効果が高くない可能性があります。しかし、新しいWebアプリ開発プロジェクトはどうでしょうか?これらのルールは、プロダクションに入る前にプログラムで適用できますか
  • これらの攻撃を100%防止するこれらのルールについての私の想定は間違っていますか?

参照:

3
ansichart

決して不可能なことはありません。

しかし、SQLインジェクションの脆弱性は、最も一般的な間違いを防止するORMとクエリビルダーによって低下しました。私の経験では、デフォルトで安全な(ish)テンプレートエンジンを使用するアプリケーションでも、XSSの問題は少なくなっています。

しかし、主な問題は次のとおりです。

  • すべてのコンテキストの入力を無害化できないため、入力の無害化はすべての問題を解決することはありません。
  • それはシンクで適切な処理を残します。安全でないすべての関数呼び出し(たとえば、ネイティブquery)にフラグを立てる必要があります。準備されたクエリに変数を含めることはできず、例外を作成することもできません(入力はユーザーではありません-制御されているので問題ありません」、「[...]」というまれな状況では、すぐに管理できなくなります)。これにより、開発者の使いやすさが大幅に制限されます。
  • XSSは非常に用途が広く、すべてのケースをテンプレート化(DOM XSSなど)で防止できるわけではありません。

例:SQLインジェクション

PHP=の例を見てみましょう。さまざまなSQL関数(queryなど)のすべての使用にフラグを付け、prepareの使用のみを許可できます。また、変数がprepareに渡されていないことを確認する必要があります。

$stmt = $conn->prepare("SELECT test from table WHERE x=?");
$stmt->bind_param("s", $test);

しかし、テーブル名を可変にしたい場合はどうでしょうか?それとも、最初に作成する必要がある複雑なクエリの場合はどうでしょうか。例えば:

$filterquery = " WHERE ";
for ($filter in $filterarray) {
    $filterquery = ...
}

$stmt = $conn->prepare("SELECT test from $tablename" . $filterquery);
$stmt->bind_param("s", [...]);

$filterqueryが安全かどうかを確認することは簡単ではないため、これは許可することができませんでした。ただし、クエリで変数を許可しないと、開発者が厳しく制限されます。

クエリビルダーを使用して、バインディング関数のみがパラメーターを受け入れることを確認できます(例:DoctrineのsetParameter)。ただし、変数がwhereなどの他の関数に渡されないようにする必要があります。 。これには正当なユースケースがあるため、開発者の使いやすさも制限されます。

例:XSS

XSSでは、これはさらに困難になります。まず、データを出力するすべての関数をチェックし、それを防止する必要があります(echoprintdieなど)。出力はテンプレートを介してのみ実行できますエンジン(これは確かに実行可能です)。

ただし、テンプレートの外部でHTMLコードを動的に構築することはできません。複雑な変数をそれに渡すことができないためです(データが(部分的に)ユーザー制御であるかどうかを知る方法がありません)。

XSSの多くのケースを防ぐために、デフォルトでデータをHTMLエンコードできるようになりました。しかし、JavaScriptのコンテキストにいるかどうかはどのようにしてわかりますか?またはsrc属性コンテキスト(javascript:リンクを防ぐ必要がある場所)?これも簡単に確認できます(または、変数が出力されるコンテキストにフラグを付ける必要があります。これはエラーが発生しやすくなります)。

そして DOMベースのXSS があります。また、一部のユーザーがHTMLの限られたサブセットを投稿できるようにしたい場合があります(これはフィルタリングできますが、テンプレートで例外が必要になります)。

5
tim