💉

SQLインジェクションとは

2024/02/27に公開

はじめに

SQLインジェクションについて学んだのでメモとして残します

SQLインジェクションとは

SQL文に外部からの入力を不正に組み込むこと
想定外のSQL操作によって情報の漏えいや改ざん、不正ログインなどが起きうる

不正ログインの例

以下のSQL文でログイン認証をしているとします
入力されたusername, passwordのペアを探しており、そのユーザーでログインする目的で使われています

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

ある実在するユーザーのパスワードを知らない状態でフォームのパスワード入力欄に' OR '1' = '1と入力するとログインに成功してしまいます。このときのSQLは以下のようになります

SELECT * FROM users WHERE username = 'tanaka' AND password = '' OR '1' = '1';

探す順番としては、usernameがtanakaでpasswordが''のユーザーを探す、その次に'1'='1'のユーザーを探します
passwordが空でも空でなくても'1' = '1'は常に真なのでWHERE句全体が真と評価され、不正ログインが成功してしまいました

漏えいの例

以下のURLで指定したuserIdのtodosが閲覧できるとします
http://example.com/todos?userId=[userId]

その状態で以下URLにアクセスします
http://example.com/todos?userId=' OR '1'='1

すると以下のSQLが実行されてしまいます。'1'='1'は常に真なのでWHERE句全体が真になり、userIdがわからなくてもtodosが表示されてしまいます

SELECT * FROM todos WHERE userId ='' OR '1'='1';

改ざんの例

以下のURLで指定したuserIdのtodosが閲覧できるとします
http://example.com/todos?userId=[userId]

その状態で以下URLにアクセスします
http://example.com/todos?userId='; UPDATE users SET username='hacker' WHERE '1'='1'; --

すると以下のSQLが実行されてしまい、会社名が改ざんされてしまいます

SELECT * FROM todos WHERE userId = ''; UPDATE users SET username = 'hacker' WHERE '1'='1'; --...

todosの取得はしないが、'1'='1'が成り立つユーザー(=全てのユーザー)のusernameがhackerに更新されてしまいます
--で後続の処理がコメントとなり省略される

SQLインジェクションの対処法

  • SQL文はプレースホルダを使用して作る

以下のように?で書き換えて渡すようにすると脆弱性が解消されます
プレースホルダで場所を取っておいてそこに値を割り当てるだけなので構造が変更されることがなくなり、不正なSQL文の実行を防ぐことができます

Goの例
db.Query("SELECT * FROM users WHERE username = ? AND password = ?", username, password)

保険的対策

  • エラーメッセージをそのままブラウザに表示しない
    • ログにDBの種類やエラーの原因、エラーを起こしたSQL文などの情報が含まれると攻撃をするヒントとなってしまうため
  • DBアカウントに適切な権限を与える

最後に

プレースホルダーにするという手間を省いただけで何万件ものデータが漏えいするなんて恐ろしい…
もっとセキュリティを学んで安全なアプリを作れるようになりたいと思いました

間違いなどありましたらコメント頂けますと幸いです!

参考

Discussion