テクノロジー

実践で学ぶSQLインジェクション攻撃と対策

実践で学ぶSQLインジェクション攻撃と対策

SQLの基本(SELECT文など)を理解している前提でこの記事を書いています。 ハッキングは犯罪です。実際に試すのはセキュリティチェックの意味を込めて自分で作ったアプリだけに留めましょう。また以下の実践的なSQLインジェクションはすべてRangeForceのラボ上で行われています。

SQLインジェクションとは

簡単にいうとWebアプリで使われているSQLを悪用してデータベースのシステムを不正に操作すること。管理者じゃないのに管理者としてログインしたり、他のユーザーのパスワードを盗んだり本来公開されていないデータへ不正アクセスすることができてしまうなかなか怖いものです。

SQLインジェクション(英: SQL Injection)とは、アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。(Wikipediaから引用)

ちなみにSQLインジェクションは開発側が理解していればちゃんと対策ができるものなので実際そこまで怖くありません。文字で読んだだけだったり初心者には理解しづらいと思うので実際にハッキングがどう行われるのか見てみると分かりやすいです。

実践してみる

ほとんどのサイトにはサイトだとログインページにユーザーネームとパスワードのフォームがあります。ログイン時にフォームで入力された情報をそれぞれusernameとpasswordという名前の変数に代入して、usersという名前のデータベースとマッチするなんていうコード書いていませんか?

SELECT * FROM users WHERE username='$username' AND password='$password';

論理的に考えて確かに正しくて分かりやすい、でもセキュリティという観点から見るとガバガバすぎてインジェクションし放題のハッカー天国です。

アタックしてみる

image

今回は上記のSQLが使われていることを想定しているので、**test' AND 1=1; –**という文字列をユーザーネームにいれたので$usernameにこれが代入されているはずです。 ここで実行されるSQL文を考えてみましょう。

SELECT * FROM users WHERE username='test' AND 1=1; --' AND password='$password';

見るからに通ってしまいそうなヤバイSQL文ができあがりました!本来ならユーザーネームとパスワードがANDで繋がれているので両方が一致していないと通らないはずの条件も一部コメントアウトされたことですべて通ってしまいます。–や#はSQLではコメントアウトになってしまうので、本来のパスワード一致を確認する部分はすべて無視、つまりパスワードになにを入れようがログイン成功できてしまいます。よく見るとAND 1=1も別にいらないです。ここで本当に必要なのはパスワード部分をコメントアウトすることだけです。

SELECT * FROM users WHERE username='test' AND password='randompassword' or '1'='1;

他にもパスワードがなんであろうと1が1であるために通るSQL文で突破する方法もあります。特殊文字が入力できないなどの理由でコメントアウトさせてもらえない場合はこっちのほうが通りやすいかもしれません。

アタックできそうかを探す

ここまでアタック方法を書きましたが、そもそもアタックできそうかの見極めも大事です。いまどきのサイトはそもそもSQLインジェクションの対策ぐらいされているし、そもそもハッキングは犯罪行為なので一般のサイトで試してはいけませんが、SQLインジェクションが出来そうなサイトはSQLっぽい文をフォームに入れると変な挙動を起こしたりします

image

ユーザーネームに’を入れてみました。

image

なんだかログイン画面に出てきてはいけなそうなSQLエラーが出てきていますね。よく見ると’が多すぎるのでエラー。これでこのサイトはSQLインジェクション対策を全くしていないということが分かってしまいます。

SELECT * FROM users WHERE username=''' AND password='password';

ちなみに中はこんな感じのコードになっているのでもちろんエラーが出る。

もっと権威が欲しい

せっかくインジェクションするのであれば、適当なユーザーよりも管理者になりたい人がほとんどだと思います。先ほどtestというユーザー名でしたが、adminで通る場合もあります。多分そいつが管理者で間違いないです。もしくはIDで探してみましょう。AUTO INCREMENTを使ったIDなら、管理者のIDは多分1です。GUIDの場合は通用しないネタです。

SELECT * FROM users WHERE username='test' OR id=1; --' AND password='$password';

これで通ったら管理者はもちろん、すべてのユーザーにアクセスし放題(usernameを知らなくても良いため)ですね。

対策

ここまで攻撃ばかり書いてきましたが**じゃあ対策はどうすればいいの?**という疑問が湧く人も多いはず。答えは簡単、文字のすべてエスケープすればすべて解決します。細かい実装方法は言語やフレームワークによっても異なりますが、簡単にエスケープ機能はつけられるはずです。

ざっくりまとめると

  • プロダクションでエラー文を表示しない
  • すべての文字をエスケープする
  • 入力できる文字のホワイトリスト(ブラックリスト)を作る
  • プリペアドステートメントを使う
  • 権限を最小限にする などがあります。まず一番はユーザーに自由に入力させないこと、必ずバリデーションチェックしましょう。

まとめ

何度も書いていますが、実際には行わないでください。 他にもインジェクションの種類はたくさんありますが、今回は基本中の基本のようなSQLインジェクションを紹介してみました。是非あなたのサイトで確認してください!もしインジェクション出来てしまうようであればしっかり対策してセキュリティを改善しましょう。

ユニオンセレクトを使ったをSQLインジェクションについての記事も書きました。あわせてお読みください。

参考にしたサイト