5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SQLインジェクションのエスケープ処理をRailsがどんな感じで実装しているか見に行った記録

Last updated at Posted at 2023-10-08

はじめに

こちらの記事では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行目あたりで与えられた値の型に応じてエスケープしてクォートしているように見えますね。

activerecord/lib/active_record/connection_adapters/abstract/quoting.rb

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を使って解説してもらいました。)

activerecord/lib/active_record/connection_adapters/abstract/quoting.rb

      # 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のコードを見たのは恥ずかしながら初めてなのですが、コメントがしっかり書いてあって本当にありがたかったです。開発された方々、本当にありがとうございます。

5
4
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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?