Postmanでログイン認証

Rails のバージョン:5.2

Rails のログイン認証画面に Postman で Post してログイン認証をやってみた。
すると、ActionController::InvalidAuthenticityTokenが出た。

Rails の CSRF 対策によるもの。

CSRF とは

A さんがプロジェクト管理サービスにログイン

ログアウトせずに、そのまま掲示板サイトを閲覧

とある書き込みをブラウザが読み込む(<img src="http://pj-service.com/project/1/destroy>)

ブラウザから上記 URL に対してリクエストが走る(このとき、まだ有効な Cookie が送信されるため認証後の画面でもリクエストが通ってしまう)

A さんが知らないうちにプロジェクトが削除されている。

ブラウザが異なるドメインからのリクエストでも、そのドメインで利用できる Cookie がある場合送信するというブラウザの仕様を突いたものみたいだ。

Rails セキュリティガイド - Rails ガイド

CSRF 対策とは

GET 以外のリクエストにセキュリティトークンを追加することで、Web アプリケーションを CSRF から守ることができます。

Rails セキュリティガイド - Rails ガイド

下記をアプリケーションコントローラに設定することで CSRF 対策が有効になる。

protect_from_forgery with: :exception

ちなみに Rails5.2 以降ではデフォルトで有効になっているみたいで定義はされていなかった。

Rails5.2 以降では ActionController::Base 内で有効になっているため、デフォルトの設定でよければ自分で記述する必要はない

Rails の CSRF 対策について - Qiita

具体的には下記のことをやってみるみたいだ。

rails は、get 以外の動詞のリンクに、authenticity_token というパラメータを自動的に付け加えます。get 以外の動詞の各アクションで params[:authenticity_token]と session[:csrf_id]を比較して、同値であれば OK としているようです。*1 同値でなければ ActionController::InvalidAuthenticityToken という例外がでます。

CSRF の対応について、rails 使いが知っておくべきこと - おもしろ web サービス開発日記

CSRF 対策が有効のままでどう認証を突破するか

本題です。

Postman で Rails の認証を突破する方法ですが、ググってもそもそも CSRF 対策を無効にしようみたいな記事ばかりだったので今回自分でいろいろ試してみました。

その1:authenticity_token と ID と Password を Postman から送信してみる

CSRF トークンは HTML に埋め込まれているので、ログイン画面の CSRF トークンを取得。
ブラウザのコンソールで下記を実行すると取得できます。
HTML 要素なので目視で探してもいいです。

document.getElementsByName('csrf-token')[0].content

次にブラウザのコンソールを開いたまま画面から実際にログインしてみます。

ネットワークタブから該当のアクセスを探して、Headers > Form Data を見ます。

authenticity_token
user[login]
user[password]

が送信されています。

同じように上記のパラメータを Postman からログイン画面に Post してあげればよさそうですね。

ログアウトして、authenticity_token は新しいものを取得しましょう。

これで送信してみますがダメでした。

その2:画面でログインして、ログイン後のセッションを使う

ブラウザのコンソールを開いたまま画面から実際にログインします。

ネットワークタブからログイン後のページのアクセスを探して、Headers > Request Headers > Cookie を見ます。

_src_sessionのキーと値をコピーします。
Postman の Cookies に追加します。

この状態でログイン認証が必要なページに GET すると、なんと成功します。

ログイン認証後のセッションがあれば問題なくログインできるようですね。

その3:ブラウザのセッション情報を Postman と同期する

その2の方法でもよいですが、毎回面倒です。

ブラウザのセッション情報を Postman と同期する方法がありました。

Postman で Cookie が必要な API を実行する - ユニファ開発者ブログ

この方法なら、画面でログインするだけで Postman に認証後のセッション情報が同期されているので、先ほどの面倒な手順なくリクエストを投げれば成功します。

逆に画面でログアウトすれば認証が必要なリクエストの場合は失敗します。

まとめ

セッションさえ偽造できればログイン後の画面にアクセスできる。
ブラウザは毎回送信できる Cookie があれば送信している。
Postman とブラウザのセッション情報を同期すれば認証後の画面へのリクエストが思いのままに投げられる。

本来は API を投げる際はトークン認証とかなのですがそういった実装がなくとりあえずログイン認証後の画面の URL にリクエスト投げたい場合の TIPS でした。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。