LoginSignup
2
0

More than 3 years have passed since last update.

RailsにおけるSQLインジェクション対策について - Rails Tutorial リスト13.46

Posted at

はじめに

Rails Tutorialを進めていく中で気になったところを記事にして残してます。

記事に間違いがある場合は教えてください:grin:

用語解説

SQLインジェクションとは

SQLインジェクションは、Webアプリケーションのパラメータを操作してデータベースクエリに影響を与えることを目的とした攻撃手法です。SQLインジェクションは、認証をバイパスする目的でよく使われます。他にも、データを操作したり任意のデータを読み出したりする目的にも使われます。

Rails セキュリティガイド - Railsガイド

つまり、ログインフォームや投稿フォームなどでSQLのデータを処理する際に、不正(サーバーからみると正常)なデータが実行されてしまうことです。
これによってログイン偽装やデータの抜き取りが起こります。

エスケープ処理とは

「'」「"」「NULL」「改行」などのSQL文において都合の悪い文字を使えなくすることです。

悪い例

不正に認証が通ってしまう

以下のコードでログイン処理をするとしましょう。

User.find_by("login = '#{params[:name]}' AND password = '#{params[:password]}'")

一見問題はなさそうに見えますが、もし以下のパラメータが入っていたとします。

params = { name:     "' OR '1'='1",
           password: "' OR '2'>'1" }

これを実行すると以下のようなSQL文が呼ばれることになります。

SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '' OR '2'>'1' LIMIT 1

要約すると1=1, 2>1が成り立つ時usersから1人取り出してくださいということです。
ログインとしての機能を果たさなくなってしまいました。

原因

こうなってしまう原因はエスケープ処理をしていないからです。

対策

対策としてSQL文を書くときには直接文字列を代入するのではなく、必ずエスケープ処理をするようにしましょう。

エスケープ処理には以下の方法があります。

  1. 配列、ハッシュとして渡す。(モデルのインスタンスのみ)
  2. sanitize_sql()を使う。(それ以外)

対策1

モデルの場合はこちらが楽です。

# 配列
Model.where("login = ? AND password = ?", entered_user_name, entered_password).first

# もしくはハッシュ
Model.where(login: entered_user_name, password: entered_password).first

対策2

sanitize_sqlというメソッドでエスケープできます。

# 3つの例
sanitize_sql(["name=? and group_id=?", "foo'bar", 4])

sanitize_sql(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])

sanitize_sql("name='foo''bar' and group_id='4'")

参照

Rails セキュリティガイド - Railsガイド
ActiveRecord::Sanitization::ClassMethods - Rails API

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0