web-dev-qa-db-ja.com

ハッシュによりSQLインジェクションを防ぐことができますか?

気まぐれで、最近開発したローカルWebサーバーに、最初に作成した適切なWebサイトをスローすることにしました。私は欠陥があり、サイトは本当に私自身の個人的な開発のためだけに意図されていたので、SQLを投入するのに最適な環境だと思いました。

とにかく、要点を理解するために、数回の試行の後、ページでステートメントのエラーを返すようにすることができました。私がセットアップした特定のテストアカウントにアクセスしようとしました(結果が複数のアカウントを返し、エラーがスローされた場合、1 = 1で機能するすべてのユーザー名を選択することを期待していませんでした)が、毎回通常の誤ったパスワードを入力したかのように応答します。 PHP=コードを調べたところ、クエリの前にパスワードをハッシュしていたため、攻撃が害を及ぼす前にハッシュされていたことがわかりました。

全体としてWebセキュリティに不慣れで、Web開発に関心を持っているので、この方法 SQLインジェクション 防止に脆弱性があるかどうか考えていました。明確にするために、これは「私が何か新しいものを見つけた人を見て」という意味ではありません。情報セキュリティには、これをすでに理解していると思われるよりもはるかに明るいスパークがあるからです。これがセキュリティメカニズムとしてふさわしくない理由を知ってください。

22
lewis

したがって、クエリに入力する前にユーザーパスワードをハッシュすることは、SQLインジェクションを防ぐための偶発的なセキュリティ機能ですが、すべてのユーザー入力でこれを実行できるとは限りません。顧客を名前で検索していて、次のようなクエリがある場合

Select * from Customer Where Name like '%userInput%'

入力されたもののハッシュバージョンとしてuserInputを設定した場合、Nameもデータベースでハッシュされていても正しく機能せず、正確な検索クエリに対してのみ機能します。したがって、「Sue」という名前のお客様がいて、「sue」という検索を入力した場合、それは機能しません。また、検索で完全に一致しない限り、顧客の名前もわかりません。これは実用的ではありません。

SQLインジェクションを防ぐ方法は、上記のようなクエリを作成しないことです。入力を処理してクエリにパラメーター化し、= sや入力のコンテキストでは意味をなさないその他の記号などを取り除きます。 。 SQLインジェクションを防ぐための適切なガイドは、 ここ にあります。

36
Ryan Kelso

基本的にはい、SQLに渡す前に入力(16進数またはBase64形式で表される)をハッシュすると、効果的なSQLi攻撃ベクトルにはなりません。入力をparseIntした場合も同様です。これらは、便利なSQLiに必要な文字をサポートしていません。 (つまり、引用符で囲まれた文字列から抜け出すため)

この手法の実用性は限られています。つまり、LIKE<>などの有名なSQL機能の一部とは互換性がありません。
またはインデックス付き等式検索(=および<>インデックスを使用)

余談ですが、パスワードハッシュ 本当にソルトする必要があります であることを指摘しておきます。あなたの例でその基準が満たされた場合、SQL WHERE句にハッシュを含めることはもうなくなると思います。

7
Bryan Field

あなたが(偶然に)行っていることは、「入力のサニタイズ」として知られているものの一部です。これは、すべてのアプリケーションが欠陥(つまり、脆弱性)を減らすために取るべきステップです。

アプリは最初に、入力がアプリのデータを受け入れる能力をオーバーフローしないことを確認する必要があります。これは、入力の長さをチェックするか、サイズが大きすぎるデータを拒否することを意味する場合があります。

次に、アプリは、可能であれば、ホワイトリストに対して入力をチェックして、不要な入力がロジックに入らないようにする必要があります。場合によっては、入力に有効な英数字のみが含まれていることを意味する場合があります。しかし、ホワイトリストはその特定の入力フィールドでは意味をなさない場合がありますが、開発者はインジェクションを防ぐ必要があるため、ブラックリストを組み込んでいます。ブラックリストは、入力を可能にすることがわかっているシンボルが入力に含まれていないことを検証します。ブラックリストの欠点は、開発者がブロックすることを知っているものに対してのみ保護することです。例としては、SQLインジェクションを防ぐために引用符を停止するブラックリストがあります。しかし、開発者は、エンコードされたURLを入力が通過するときに、%27が引用符になることを認識しない場合があります。

内部的には、アプリケーションは、さまざまな形の注入を防ぐために防御的に書かれる必要があります。 (連結を使用してSQLクエリを構築する代わりに)パラメータ化されたSQLを使用すると、SQLインジェクションを防ぐのに役立ちます。しかし、ユーザー入力のある他の多くの場所は、さまざまな種類の注射に対して脆弱である可能性があります。攻撃者が"..\..\..\..\..\..\windows\cmd.exe"のようなものを入力した場合、ディレクトリパスが影響を受ける可能性があります。XPathクエリが挿入され、不正なデータが改ざんされる可能性があります。また、JavaScriptはデータベースを通過して、被害者のブラウザを改ざんする可能性があります。他の防御形態には、出力で内部診断エラーメッセージを明らかにしないこと、および潜在的な攻撃者の特定を支援するためのロギングが含まれます。

アプリが行ったことは、最初に入力をハッシュルーチンに渡すことです。これは、データをサニタイズし、SQLステップに到達する前にデータの長さを制限するという二重の効果があります。ハッシュルーチンへの入力は依然としてバッファオーバーフローに対して脆弱である可能性があることに注意してください。攻撃者が"aaaa[...repeated 1000 times...]aaaa_Evil_Injection_Here"のパスワードを入力するとどうなりますか?アプリはまだそれを処理する必要があります。

1
John Deters

他の多くの学習者と同様に、ストレージトランスポートを混同しています。そして、後者を保護するために、前者を故意に台無しにしています。

SQLインジェクションは、理由のために「データベースインジェクション」と呼ばれていないことを理解する必要があります。データベース、ストレージを保護する必要はありません。保護する必要があるのはトランスポート、つまりSQLクエリだけです。ストレージはデータをそのまま保存できる必要がありますが、そうでなければまったく価値がありません。あなたstillがそのステートメントの証拠を必要とする場合、

  • 自作の「保護」を知らないさまざまなクライアントがいる可能性があります
  • 厳密な比較だけでなく、比較だけではありません。データが関係している可能性のあるステートメントが存在します:算術、部分文字列検索、さまざまな変換、文字列操作、あらゆる種類の計算
  • データベースは、データを保存するだけでなく、それを操作するためにも使用されます。ハッシュ化されたユーザー名をorderしてみてください
  • 結局のところ、データベースからデータを印刷する必要がある場合があります

そのため、保存されたデータを何らかの方法で変更する保護手段はすべて間違っていると言えます。そして、あなたの考えは単によく考えられていません。

1

ハッシュは、バイナリ出力をエンコードして文字列に戻すステップにより、パスワードフィールドへのSQLインジェクションを保護します。

この保護は通常は役に立ちませんが、次の前提条件に当てはまる場合は十分です。

  • アプリケーションは、ユーザー名とパスワード以外の文字列を処理しません。
  • 'および\文字のユーザー名を削除します。

これらのいずれかが当てはまらない場合、または将来的に当てはまる可能性がある場合、ハッシュは有効な防御手段ではありません。これにより、Webアプリケーションの99.9%が排除されます。

0
Joshua