はじめに
こちらの記事ではSQLインジェクションが何かについては解説していませんので、詳しく知りたい方はRailsガイドをご覧下さい。
記事を書いた動機と概要
Railsガイドを読んでいて、SQLインジェクションについて読んでいるとRuby on Railsには、特殊なSQL文字をフィルタが組み込まれており、「'」「"」「NULL」「改行」をエスケープします。
と書かれていたので、それってどこで、どうやって実装しているんだろう?と疑問に思って調べてみたので、その過程をつらつらと書いています。
はい、ほぼ独り言です。
下記は疑問に思った部分をRailsガイドから引用しています。
7.2.4 対応策
Ruby on Railsには、特殊なSQL文字をフィルタが組み込まれており、「'」「"」「NULL」「改行」をエスケープします。Model.find(id)やModel.find_by_なんちゃら(かんちゃら)といったクエリでは自動的にこの対応策が適用されます。ただし、SQLフラグメント、特に条件フラグメント (where("..."))、connection.execute()またはModel.find_by_sql()メソッドについては手動でエスケープする必要があります。
条件オプションに文字列を直接渡す代りに、以下のように配列を渡すことで、汚染された文字列をサニタイズすることもできます。
Model.where("login = ? AND password = ?", entered_user_name, entered_password).first
疑問符「?」が含まれていますが、これはプレースホルダと呼ばれるもので、Railsに関わらず一般的な用語としてクエリやテキストなどにおいて、後から実際の値と置き換えられるシンボルや変数のことみたいです。RailsのActiveRecordにおいても?
記号はプレースホルダとして使われているようで、プレースホルダを見つけたら、対応するパラメータ(この場合 entered_user_name と entered_password)を取得して、それぞれを安全にエスケープするぞ!ってなるようで、そのエスケープ処理がどこで記述されているか調べていきました。
Railsのコードを見に行ってみる
まず、Railsのリポジトリhttps://github.com/rails/rails で該当のファイルに辿り着かねば、というところで「injection」とか調べる訳ですが、結論「SQL_injection」と検索するとそれらしきコードには辿り着けました。
こちらが、そのファイルです。
エスケープ処理を読んでみる
下記の14行目あたりで与えられた値の型に応じてエスケープしてクォートしているように見えますね。
module ActiveRecord
module ConnectionAdapters # :nodoc:
# = Active Record Connection Adapters \Quoting
module Quoting
# Quotes the column value to help prevent
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
def quote(value)
case value
when String, Symbol, ActiveSupport::Multibyte::Chars
"'#{quote_string(value.to_s)}'"
when true then quoted_true
when false then quoted_false
when nil then "NULL"
quote_string
メソッドを呼んでいたので見に行くと、コメントにも書いてあるのですが、文字列中のバックスラッシュとシングルクォートをエスケープしているというのが分かりました。(ここ自分はChatGPTを使って解説してもらいました。)
# Quotes a string, escaping any ' (single quote) and \ (backslash)
# characters.
def quote_string(s)
s.gsub("\\", '\&\&').gsub("'", "''") # ' (for ruby-mode)
end
最後に
そんな感じで(どんな感じだよ)、Railsガイドに書いてあった特殊なSQL文字をフィルタが組み込まれており、「'」「"」「NULL」「改行」をエスケープします。
の部分の処理がされているんだなということがフワッと分かったところで、本日はお開きにしたいと思います。
今回ちゃんとRailsのコードを見たのは恥ずかしながら初めてなのですが、コメントがしっかり書いてあって本当にありがたかったです。開発された方々、本当にありがとうございます。