2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Railsセキュリティ基礎メモ

2
Last updated at Posted at 2026-02-11

はじめに

フレームワークを使っているとつい意識が薄くなりがちなセキュリティ関係の知識のメモ

本編

XSS

Cross Site Scriptingのこと。
Javascriptを埋め込まれ、対策をしていないとそれが実行され、さまざまな悪影響につながる。

被害例

Javascriptでできることはなんでもやられてしまうと思って良さそう。

  • 悪意あるサイトに勝手に飛ばされる
    • <script>location.href="https://example.com/"</script>
  • 別のユーザーの入力した内容(パスワードなど)が攻撃者のサーバーに送信され、情報漏洩につながる
  • Cookieが読み取られてしまう
    • document.cookie

手口

  • 入力フォーム
    • 悪意あるスクリプトを入力して送信したり、DBに保存された値がスクリプトで、画面に表示した時に実行されてしまう、など
  • HTMLアトリビュート
    • aタグのhrefにユーザーの入力値を適用する場合、注意が必要
    • <a href="javascript:alert('XSS')"></a>
      • 事前に入力値のチェックをする処理をする必要がある

原因

ユーザーの入力した内容がHTMLのタグやJavascriptとして認識され、実行されてしまうことによるため。

Railsの対策

基本的には自動でやってくれているので、意識する必要はない。
Railsのviewでよくみる下記は、自動でエスケープ処理をしてくれる。
HTMLエンティティを自動的にエスケープしてから、ActiveSupport::SafeBufferを利用して文字列を結合し、レンダリングする。

test.erb
<%= @comment %>

【エスケープ処理とは?】

特定の文字列や文字を、別の文字列に変換する処理のこと。

例えばこんな感じ

> → &lt
< → &gt
" → &quot
' → &#039

実装面での注意

入力値にはバリデーションチェックを設けること

rails-ujsを使用している場合

test2.erb
<%= link_to '削除する', user_path(@user), method: :delete, data: { confirm: "#{@user.name}を削除しますか" } %

data属性やmethod属性はエスケープされない。
上記の@user.name部分。
sanitizeやhメソッドを使って自前でエスケープする必要がある。

link_toを使用する場合

デフォルトでエスケープ対象とならないぽい?
下記の@user.linkのところ。
https://techracho.bpsinc.jp/hachi8833/2022_05_31/25326

test3.erb
 <%= link_to “LINK”, @user.link %>

エスケープ処理をしたくない時(注意!!)

html_safe raw <%==

完全にエスケープを回避したい場合に使う。

test4.erb
<%= @comment.html_safe %>

<%= raw @comment %>

<%== @comment %>

使う時は、下記のようにあらかじめエスケープする処理と組み合わせることが多い。

test5.erb
h(@comment).gsub("\n", '<br>').html_safe

sanitize

ある程度タグをそのまま出したいものの危険なタグは出力しないようにしたい場合に使う。
例えば、改行、太字、斜線は有効にしたいときとか。
デフォルトで有効になるタグもあるが、オプションで、ホワイトリストにタグを追加することも可能。

test6.erb
<%= @comment.sanitize %>

DOM-based XSS

ブラウザ上で動くJavaScriptによって発生する種類のXSSのこと。
JavaScriptによってHTMLを操作・生成する実装をする時に発生する可能性がある。

div = document.getElementById("test");
div.innerHTML = location.hash.substring(1); 

CSRF

クロスサイトリクエストフォージェリのこと。
悪意のあるユーザーがサーバーへのリクエストを捏造して正当なものに見せかけ、認証済みユーザーを装うという攻撃手法。
善意のユーザーがログインしている状態で、別のサイトに用意したコンテンツ上にある罠のリンクを踏ませること等をきっかけとして、本人が気づかないところで、不正なコード(予期しないリクエストを送る)を実行させ、何かしら被害を被らせること。

被害例

Railsの対策

サーバーがリクエストを受け取ったときに、そのリクエストが本当にユーザーの意図したものかを判別する必要があります。

form_withなどを使用するフォームでは自動でauthenticity_tokenが埋め込まれ、入力された値と合わせてサーバに送られる。
「発行したトークン」と「送られてきたトークン」が一致するか確認することで、正規の入力フォームからの入力かを判断する仕組み。

ちなみに、一致の確認のためには、セッションに含まれる_csrf_tokenが使われており、これと「送られてきたトークン」を比較している。

ApplicationControllerにprotect_from_forgeryを追加することで有効になる。(今はデフォルトでONなので書く必要はない)

test7.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

HTMLヘッダーには以下が含まれ、Ajaxリクエストなどでもトークンを利用できるようにしています。

test8.erb
<%= csrf_meta_tags %>

ActionController::InvalidAuthenticityToken例外が発生した時

トークンが一致しないと上記エラーが出るので、下記のようにコントローラーに書くと無効化できる。

test9.rb
class ApplicationController < ActionController::Base
  skip_before_action :verify_authenticity_token
end

外部からのAPIアクセスの時のみ解除するなどし、無闇に無効化しない。
(例えば、フロントを分離したSPAなどの場合、

タグに仕込んでいるauthenticity_tokenの値をajaxリクエスト時に送るようにするなどするのがメジャーな方法らしい)
また、解除するときはAPIトークンやJWTによる認証を大体手段として検討すること。

実装面での注意

GETとそれ以外を適切に使い分ける

攻撃に利用されるのは、POST PUT PATCH。
また、GET内で状態変更する機能を作ること自体を避けること。

Rails8.2からの変更点

トークンを使わない方法に変わるかも。
https://blog.willnet.in/entry/2025/12/15/192245

SQLインジェクション

攻撃者がSQL文に不正なクエリを注入することで、攻撃を行うこと。
ユーザーからのパラメータを検証せずにSQLに組み込んでしまうと、意図しないSQLが実行されてしまう。

例えば、' OR '1'='1を仕込む手法が有名。

被害例

  • 任意のレコードを参照されてしまう(別ユーザーのパスワードとか)
  • 勝手にデータを消されたり、更新される

Railsの対策

ActiveRecordは、自動的にパラメータのエスケープ処理を行い、安全なSQL文を生成する。
基本は下記のようにハッシュで渡す方法を用いること。

test10.rb
user = User.where(email: params[email]})

実装面での注意

複雑なクエリのためにハッシュを使えない場合、Placeholderを使う

test11.rb
user = User.where(["user_id = '?', current_user.id]})

SQLのLIKE演算子を使う場合はActiveRecord::Base.sanitize_sql_likeを使用する

おまけ find_by_*の脆弱性

昔のRailsではSQLインジェクション脆弱性があったらしい。
https://blog.tokumaru.org/2013/01/Ruby-on-Rails-find-by-method-SQL-Injection-CVE-2012-5664.html

HSTS

HTTP通信→通信内容(URLの一部、送受信データ、認証情報など)が暗号化されないため、途中で盗み見(盗聴)や改ざんされるリスクがある。
HTTPS通信→SSL/TLSで暗号化された安全な通信

最近ではHTTPS通信が一般的になっている。

HSTSとは、レスポンスヘッダにStrict-Transport-Securityを付与することで行われる。
ブラウザはStrict-Transport-Securityヘッダーを受け取るとそのサーバーのドメインを記憶し、以後そのドメインにアクセスするときは、たとえhttp://を指定した場合でもHTTPS通信にリダイレクトを試みるようになる。

Railsの対策

config/environments/production.rbでconfig.force_ssl = trueと設定すると有効になる。

現在はproduction環境において、デフォルトで有効。

マスアサインメント

攻撃者がフォームのパラメータに任意のキーと値を設定して送信すること。
フレームワークの自動マッピング機能を悪用するもの。
例えば、以下のような方法で任意のパラメータをサーバーに送信できる。

  • 開発者ツールのElementsパネルで任意のinputタグを追加後、フォームを送信
  • 開発者ツールのConsoleパネルで任意のフォームデータを生成し、fetch APIでサーバーにリクエストを送れてしまう

被害例

  • ユーザーの新規作成時、任意のレコードを作成できてしまう
    • is_adminをtrueにしたりとか

Railsの対策

Strong Parametersを使い、あらかじめ決めた任意のパラメータしか受け付けないようにすることができる。

test12.rb
def user_params
  # 許可されたパラメータのみ
  params.expect(user: [:email, :password])
end

IDOR

例えば下記のような実装。
パラメータに任意の値を入れれば、他のユーザーのデータも無制限に閲覧できる。よって、URLを改竄するだけで、簡単に他人のデータにアクセス可能。

test13.rb
def show
  @comment = Comment.find params[:id]
end

実装面での注意

そのため、他人のデータは閲覧できないという仕様が求められる場合は、下記のようにログインユーザーのデータに限定すべき。

test14.rb
def show
  @comment = current_user.comments.find_by(id: params[:id])
end

参考

https://qiita.com/toduq/items/b88716bad35865ef2dc9
https://techracho.bpsinc.jp/hachi8833/2023_09_19/133406
https://woshidan.hatenadiary.jp/entry/2021/12/12/192958
https://jpcertcc.github.io/OWASPdocuments/CheatSheets/RubyOnRails.html
https://zenn.dev/hogeisfuga/articles/e6abb1723c8271
https://techracho.bpsinc.jp/hachi8833/2021_11_26/46891
https://techblog.glpgs.com/entry/2016/09/12/165939
https://zenn.dev/cobachie/articles/rails-security
https://qiita.com/minimabot/items/69f07810dfd4f5d83015
https://cysec148.hatenablog.com/entry/2025/03/21/165021

2
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?