実践で学ぶ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 インジェクションについての記事も書きました。あわせてお読みください。

参考にしたサイト

Comments

コメントを読み込み中...

コメントを残す

返信先:
0/2000文字