🤖

RailsでのSQLインジェクションに対し考慮したいこと

2023/12/15に公開

この記事は ゲームエイト開発部 Advent Calendar 2023 の記事です。

RailsにおけるSQLインジェクションの防止

はじめに

弊社では開発のバックエンドにRailsを採用しています。
Railsではデフォルトにて脆弱性対策がされていますが、書き手側で考慮しないといけないこともあります。
今回はその中でもSQLインジェクションに絞って話をしていきます。

SQLインジェクションとは

SQLインジェクションは、攻撃者が不正なSQLコマンドをデータベースに注入し、セキュリティを侵害する攻撃手法です。一般的な攻撃例として、ウェブフォームからの攻撃が挙げられます。
例えば、ログインフォームに

' OR '1'='1

といったSQL文を注入することで、認証メカニズムを回避し、不正アクセスを行うことが可能です。
これはデータベースからの機密情報の漏洩やデータの不正改ざんにつながる可能性があります。

RailsにおけるデフォルトのSQLインジェクション対策

Railsは、Active Recordを通じてSQLインジェクション攻撃を防ぐためのメカニズムを提供しています。

Active Recordクエリメソッド
app/models/user.rb におけるActive Recordクエリの例:

class User < ApplicationRecord
  # ...

  def self.find_by_name(name)
    where("name = ?", name)
  end
end

このコードでは、whereメソッドがプレースホルダー(?)を使用しており、Railsが対応する値をエスケープします。

Named Parameter
名前付きパラメータの使用例:

class UsersController < ApplicationController
  # ...

  def show
    @user = User.find_by(name: params[:name])
  end

Railsはパラメータを自動的にサニタイズします。

RailsにおけるSQLインジェクション対策の不足点

Railsのデフォルト機能だけでは全てのSQLインジェクションリスクを防ぐことはできません。開発者は以下の点に注意する必要があります。

パラメータのサニタイズ:

直接SQLクエリにユーザー入力を含める際は、そのパラメータをサニタイズすることが重要です。Railsでは、プレースホルダを使用してパラメータを安全に組み込むことができます。

# 安全でない方法
name = params[:name]
User.where("name = '#{name}'")

# 安全な方法
name = params[:name]
User.where('name = ?', name)

ActiveRecordの利用:

RailsのActiveRecordを使用することで、SQLインジェクションのリスクを大幅に減らすことができます。ActiveRecordは、SQLクエリを自動的にエスケープし、安全な形式でデータベースに渡します。

# 安全な方法
name = params[:name]
User.where(name: name)

生のSQLクエリの使用を避ける:

可能な限り生のSQLクエリの使用を避け、ActiveRecordのメソッドを利用することを推奨します。どうしても生のSQLが必要な場合は、特に注意が必要です。

ユーザー入力の検証:

フォームやAPIを通じて受け取ったデータは、サーバー側で厳格に検証し、不正なデータがデータベースに渡されないようにする必要があります。

# 入力の検証
name = params[:name]
unless name.match?(/\A[a-zA-Z]+\z/)
  # 不正な入力を処理
end

# 安全なクエリの実行
User.where(name: name)

セキュリティ更新の適用:

Rails自体や使用しているGemのセキュリティアップデートを定期的にチェックし、最新の状態を保つことが重要です。

おわりに

Railsでは脆弱性対策が実施されていますが、すべてのシナリオで完全な保護を提供するわけではありません。開発者は、アプリケーションのセキュリティを確保するために、常に自身のコードに対し疑念を持って確認できるようにしていきたいですね。

ゲームエイトテックブログ

Discussion