クレデンシャルスタッフィングは、どこかで漏れたID/パスワードの一覧を使い回して、他サービスへの不正ログインを試みる攻撃です。 対策は単発の防御では足りず、多要素認証とレート制限を軸に複数の層で守ることで決まります。
クレデンシャルスタッフィングとは
クレデンシャルスタッフィング(リスト型攻撃):他サービスから流出したID/パスワードの組み合わせを大量に用意し、自動化ツールで次々とログインを試す攻撃です。 利用者がパスワードを使い回していることを前提に成立します。
似た攻撃にブルートフォース(総当たり)がありますが、両者は狙いが違います。 ブルートフォースが1つのアカウントに対してパスワードを無数に試すのに対し、リスト型は「正しい可能性が高い組み合わせ」を多数のアカウントに1回ずつ試すため、少ない試行で成功し、ロックアウトも回避しやすくなります。 攻撃は単一の送信元から行われる場合も、ボットネットなどを使って分散される場合もあります。 多数のアカウントへ少数回ずつ試す通信は正規のログインに紛れやすいため、単一IPや単一アカウントの失敗回数だけでは検知しにくいのも厄介な点です。
クレデンシャルスタッフィングが起きるパターン
典型的な弱点は次のとおりです。
- 多要素認証がなく、正しいID/パスワードの組み合わせだけでログインが完了する
- ログイン試行に回数制限がなく、大量の自動リクエストを送れる
- 「IDが存在しない」「パスワードが違う」とエラーを区別して返し、有効なIDを絞り込ませてしまう
- 流出済みの脆弱なパスワードでも登録や利用ができてしまう
- ログインAPIが公開され、レート制限もボット検知もなく機械的に叩ける
- ボットによる自動化を検知する仕組みがない
共通するのは「正しい組み合わせを1回当てればログインでき、試行の回数と自動化を止められていない」という点です。
対策法
原則は「パスワードだけを認証の唯一の壁にしない」ことです。
- 多要素認証(MFA)を導入し、パスワードが正しくても第二の要素を要求する。これが本命の対策になる
- IPやアカウント単位でログイン試行にレート制限をかけ、一定回数の失敗で一時的にロックする
- 既知の流出パスワードを登録時と利用時にチェックし、使い回しの弱いパスワードを弾く
- エラーメッセージを「IDまたはパスワードが違います」に統一し、有効なIDを推測させない
- 不審な試行にCAPTCHAやボット検知を組み合わせ、自動化のコストを上げる
MFAは成功率を大きく下げる一方で導入コストが見合いやすく、まず優先すべき対策です。 そのうえでレート制限とエラーメッセージの統一を重ねるのが、費用対効果の高い順序になります。
Rails での事例
レート制限は rack-attack で実装するのが定番です。 リスト型攻撃は「多数のアカウントに少数回ずつ」試すため、アカウント単位の失敗回数だけを見ていると見逃しやすくなります。 IP 単位とアカウント単位の両方でしきい値を設けます。
# config/initializers/rack_attack.rb
Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(
url: ENV.fetch("RACK_ATTACK_REDIS_URL")
)
class Rack::Attack
# 同一IPからのログイン試行を制限(分散攻撃には効きにくいが土台になる)
throttle("logins/ip", limit: 10, period: 60) do |req|
req.ip if req.path == "/users/sign_in" && req.post?
end
# 同一アカウントへの試行を制限(IPを変えて来る攻撃に効く)
throttle("logins/email", limit: 5, period: 60) do |req|
if req.path == "/users/sign_in" && req.post?
credentials = req.params["user"]
credentials["email"].to_s.downcase.strip.presence if credentials.is_a?(Hash)
end
end
end
この例はDeviseの標準ルートとパラメータ名を前提にしています。
ルートや認証キーを変更している場合は、実際のログインリクエストに合わせます。
複数プロセスや複数台で同じ制限値を共有するため、Rack::AttackのカウンタはRedisなどの共有ストアへ置きます。
IP単位の制限は、ロードバランサーやリバースプロキシを信頼する範囲が正しく設定され、req.ipを利用者が任意の転送ヘッダで偽装できないことが前提です。
Deviseを使っている場合は、lockableモジュールと利用する解除方式に必要なDBカラムを追加し、一定回数の失敗後にアカウントをロックできます。
以下は、時間経過でロックを解除する設定例です。
# db/migrate/..._add_lockable_to_users.rb
class AddLockableToUsers < ActiveRecord::Migration[8.1]
def change
add_column :users, :failed_attempts, :integer, default: 0, null: false
add_column :users, :locked_at, :datetime
end
end
# app/models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :lockable
end
# config/initializers/devise.rb
Devise.setup do |config|
config.lock_strategy = :failed_attempts
config.unlock_strategy = :time
config.maximum_attempts = 5
config.unlock_in = 15.minutes
end
マイグレーションの継承バージョンは、利用中のRailsに合わせます。
lock_strategy、unlock_strategy、maximum_attempts、unlock_inは、求める保護水準と利用者への影響に合わせて明示的に決めます。
アカウントロックは、攻撃者が既知のIDへ失敗を重ねて正規利用者を締め出すDoSにも使えるため、IPやネットワーク、端末などを組み合わせたレート制限と監視を併用します。
流出済みパスワードの拒否は、Have I Been Pwned の API と連携する devise-pwned_password のようなライブラリで、登録時とパスワード変更時に検査を挟めます。
どの対策も単体では抜け道が残るため、記事本文の順序(MFA を軸に、レート制限とロックを重ねる)で層を作ることが前提です。
まとめ
クレデンシャルスタッフィング対策の要点を整理します。
- 根本原因は「正しい組み合わせを1回当てればログインが完了すること」。パスワードの使い回しが前提にある以上、自社のパスワードポリシーだけでは防げない
- 本命の対策は多要素認証(MFA)。パスワードが正しくても第二の要素を要求すれば、リスト型攻撃の成功率は大きく下がる
- レート制限はIP単位とアカウント単位の両方に掛け、リスト型は「多数のアカウントに少数回ずつ」試すため、アカウント単位の失敗回数だけでは見逃しやすい
- Deviseの
lockableには必要なDBカラムと解除方法、試行回数、ロック時間の設定が要り、意図的なロックによるDoSのリスクを抑えるため、レート制限と監視も併用する - エラーメッセージを「IDまたはパスワードが違います」に統一し、有効なIDを絞り込ませない
- 既知の流出パスワードを登録時と変更時に拒否する。CAPTCHAやボット検知は、自動化のコストを上げる補助として重ねる
リスト型攻撃は正規のログインに紛れ、複数の送信元から分散して届くことがあるため、単一IPや単一アカウントの失敗回数だけでは検知しにくくなります。 IP、アカウント、ネットワーク、端末、複数アカウントを横断した試行傾向を組み合わせて検知しつつ、MFAという「パスワードが当たっても通らない」構造を先に作るのが費用対効果に優れます。
関連して読める記事
不正ログインが成立した後は、攻撃者は正規の利用者と同じセッションを持ちます。 そこから先の被害の広がり方は、セッションを盗まれた場合と同じ問題になります。 ログイン処理そのものの設計にはセッション固定化の観点も必要で、乗っ取られたアカウントを起点に管理機能まで到達されるかどうかは権限昇格の対策で決まります。

セッションハイジャックとは?起きるパターンと対策法
セッションハイジャックの仕組みと起きるパターン、Cookie の HttpOnly / Secure / SameSite 属性と TLS の全面適用を軸にした対策を整理します。Rails のセッションストア設定で属性を明示していない危険例と、secure・httponly・same_site を指定した安全な設定、force_ssl による HTTPS 強制と reset_session によるセッション破棄までを具体的なコードで示します。
2026年7月25日
セッション固定化とは?起きるパターンと対策法
セッション固定化の仕組みと起きるパターン、ログイン成功時のセッションID再発行を軸にした対策を整理します。Rails で認証後に session[:user_id] を代入するだけの危険な実装と、reset_session を呼んでから値を入れる正しい順序、Devise を使う場合の扱いまでを具体的なコードで示します。
2026年7月25日
権限昇格とは?起きるパターンと対策法
権限昇格(水平方向・垂直方向)の仕組みと起きるパターン、サーバ側での権限判定とデフォルト拒否を軸にした対策を整理します。画面でメニューを隠すだけの危険な実装と、管理系コントローラを共通の基底クラスへ集約する方法、Pundit の verify_authorized による掛け忘れ検出までを具体的なコードで示します。
2026年7月25日