web-dev-qa-db-ja.com

パラメーター化されたクエリの入力の無害化

どこでも完全にパラメーター化されたクエリを使用する場合、それでも入力をサニタイズする必要があるか、セキュリティに関連していますか?例えば。データベースに対してパラメータ化されたクエリを送信する前、またはテキストから特定の特殊文字を除外する前に、メールアドレスが有効であることを確認しますか?

私のデータベースから無害化されたデータを消費しようとする、良性だが十分に設計されていないサードパーティのツール(管理者が独自に作成したスクリプト、または技術者以外が作成した豪華なCrystalReports)を考えています。

現在、SQL Server(MySQLはEmojiに問題があるようです)に対する完全なUnicodeサポートがあり、そのプロパティを失うことなくセキュリティリスクを除外する方法がわかりません。

16
Alexander

いいえ、必要ありません。しかし、読んでください。

入力サニタイズは、魔法の杖をデータに振って「安全なデータ」にすることができるふりをする恐ろしい用語です。問題は、データがさまざまなソフトウェアによって解釈されると、「安全」の定義が変わることです。

SQLクエリに安全に埋め込むことができるデータは、HTMLに埋め込むには安全ではない場合があります。またはJSON。またはシェルコマンド。またはCSV。そして、それらのすべてのコンテキスト(および他の多くの)に安全に埋め込むことができるように値を取り除く(または完全に拒否する)ことは、制限が多すぎます。

だから何をすべきか?データが害を及ぼす可能性がないことを確認してください。

これを達成するための最良の方法は、そもそもデータの解釈を避けることです。パラメータ化されたSQLクエリは、この優れた例です。パラメータがSQLとして解釈されることはなく、データとしてデータベースに格納されるだけです。

他の多くの状況では、データを他の形式、たとえばHTMLに埋め込む必要があります。その場合、その特定の言語のデータは、埋め込まれた時点でエスケープする必要があります。したがって、XSSを防ぐために、データは表示時にHTMLエスケープされます。入力時ではありません。同じことが他の埋め込み状況にも当てはまります。

では、取得したものをデータベースに直接渡すだけでよいでしょうか?

多分。場合によります。

ユーザー入力について確認できることは間違いありませんが、これは状況に大きく依存します。サニタイズは明確に定義されておらず、誤用されているため、これをvalidationと呼ぶことをお勧めします。

  • たとえば、一部のフィールドが整数であることが想定されている場合、このフィールドを検証して、整数(またはNULL)が含まれていることを確認できます。
  • あなたは確かにメールフィールドでいくつかの検証を行うことができます(@の存在を確認する以外にあなたができることは多くないと主張する人もいますが、彼らは良い点を持っています)。
  • コメントに最小長と最大長を要求することができます。
  • おそらく、どの文字列にもそのエンコードに有効な文字のみが含まれていることを確認する必要があります(たとえば、無効なUTF-8シーケンスがないこと)。
  • ユーザーベースにとって意味がある場合は、ユーザー名を特定の文字に制限できます。
  • もちろん、パスワードの最小の長さは信じられないほど一般的です。

ご覧のとおり、これらのチェックはコンテキストに非常に依存しています。そして、それらはすべて、意味のあるデータになってしまう確率を高めるのに役立ちます。これは、悪意のある入力(SQLインジェクション、XSS、コマンドインジェクションなど)からアプリケーションを保護するためのものではありません。これは、そのための場所ではないためです。

ユーザーは投稿を拒否したり'; DROP TABLE users; --に変更したりせずに、自由に\'; DROP TABLE users; --を入力できる必要があります。このような「悪意のある」コンテンツをsec.SEに含めることができることに注意してください。

したがって、元の質問に答えるには:

...入力を何らかの方法でサニタイズすることは依然として必要ですか、セキュリティに関連していますか?

いいえそうではありません。ただし、データを出力する前に、必要に応じて適切にエスケープしてください。また、妥当な場合は検証を検討します。

私のデータベースから無害化されたデータを消費しようとする、良性だが十分に設計されていないサードパーティのツール(管理者が独自に作成したスクリプト、または技術者以外が作成した豪華なCrystalReports)を考えています。

次に、これらのツールに出力する前にデータをエスケープまたはフィルターしますが、データベース内のデータを変更しないでください。

しかし、実際には、これらのスクリプトは修正するか、セキュリティを考慮して書き直す必要があります。

(MySQLは絵文字に問題があるようです)

少し話題外ですが、MySQLのutfmb4文字セットを見てください;)

17
marcelm

すべての場所で完全にパラメーター化されたクエリを使用する場合でも、入力を何らかの方法でサニタイズする必要があるか、セキュリティに関連していますか?

はい。データベースに送信する前に、入力を無害化することは常に良い考えです。

パラメータ化されたクエリはSQLインジェクション攻撃からあなたを救うかもしれませんが、保存されたXSS攻撃の場合には有益であると証明しないかもしれません。ユーザーが悪意のあるJavaScriptコードをフォームに送信し、それをデータベースに正常に格納し、同じフィールドを別の場所に表示すると、悪意のあるスクリプトが被害者のブラウザで実行される可能性があります。

入力を先に送信する前にサニタイズし、クライアントのブラウザに送信する前に出力をサニタイズすることは常に良い考えです。

編集:コメントで指摘されているように、サニタイズは値のエンコード/エスケープとは異なります。ここでのサニタイズとは、データベース(またはその他のレイヤー)に渡す前に、いくつかの基本的なチェックのために入力を検証できることを意味します。たとえば、電子メールアドレスを必要とするフィールドは有効な電子メールアドレスで検証され、年齢のフィールドは整数のみで検証されます。正規表現は、ここで非常に役立ちます。これらのチェックは、バックエンドだけでなくフロントエンド(クライアント側)にも配置する必要があることに注意してください。

リッチテキストが必要なフィールドの場合、ユーザー入力が表示されるページに コンテンツセキュリティポリシー を実装できます。 HTMLサニタイザーを使用して、ユーザー入力をサニタイズすることもできます。

8
pri

はい、常に入力データをサニタイズする必要があります。衛生は、注入から保護するだけでなく、型、制限値(列挙型)、範囲などを検証することも目的としています。攻撃者がSQLを操作できない場合でも、残りの部分で望ましくない動作を引き起こす可能性があります。あなたの申請。

たとえば、攻撃者が列挙値を変更した場合、システムを操作できますか?彼らはロール、ユーザータイプなどを変更しただけですか?または、スキーマまたはデータ型(バイトv int32、int64)で受け入れられるよりも大きな値を入力すると、アプリケーションがクラッシュして、情報が公開されたり、孤立したデータが(トランザクションではなく)変更されたままになります。

3
JonnySchnittger