「react router v6 の Object-based Routes」を使うと Reactのルーティング周りがいい感じに書けて良い

最初こっちに書いてたけどQiitaに出来そうだったのでコンバート。 またこのパターン。

React Router v6 の Object-based Routes をキメると、ルーティング実装が気持ちよくなる(かもしれない)ので紹介させてほしい - Qiita

Reactアプリのログインチェック機能がまぁまぁ上手くできた話

React(SPA)でログインチェック機能がまぁまぁ上手く出来たので軽くメモを残す。
認証済みを表す状態をグローバルで保持する必要があるかと思ったが、特にそんなことはなかった。 その代わり"ログインチェック"済みかどうかを表す状態を保持することにした。

満たすべき要件

  • アプリケーションにアクセスした際、認証済みかどうかをチェックする(ログインチェック)
  • 認証済みの場合はホームページ(任意)に、そうでない場合はログインページに飛ばす
  • ログインチェックが終わるまではページを表示しない。もしくはローディング画面を表示する。

ログインチェック

  • ログインチェック用のAPIを用意する。
  • useLoginCheckというhooksを作成しAppで呼び出す。
    • useLoginCheckでは用意したAPIを叩き結果を取得する
    • 処理結果に関わらず処理は継続したいので、catchもしっかりと設定して例外で落ちないようにする。

参考

useLoginCheck
zaik/useLoginCheck.ts at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub

App
zaik/App.tsx at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub

ログインチェック用API(def show)
zaik/sessions_controller.rb at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub

ログインチェック後のページ遷移

  • useLoginCheckでAPIを叩いた結果ログインしていないことが判明したら(200OKでなかったら)、login画面に飛ばす
  • 200OKの場合はそのまま。結果的にURLで指定された任意のページが表示される。

参考

useLoginCheck
zaik/useLoginCheck.ts at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub

ログインチェック中のローディング画面。

  • ログインチェック実行済みか否かを示す、グローバルなステート(loginChecked)を用意。初期値false。
  • loginCheckedがfalseの場合、ローディング画面(ローディング用のコンポーネント)を表示するようにAppコンポーネントを修正
  • useLoginCheckでAPIを叩いた後にloginCheckedをfalseにする。

参考

大方針はこのページのやり方を参考にした
ReactでAPI通信をしている間Loading画面を表示する | Fintan

authSlice
zaik/authSlice.ts at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub

App
zaik/App.tsx at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub

備考

loginChecked ステートは loading ステートに名称を変更して、もう少し汎用的に使える形にした方が良いかもしれない。

React + Rails(API)で tokenを用いたCSRF対策の基礎(のメモ)

cookieを利用した認証を採用した場合、必然的にCSRFの対策を行う必要がある。 Railsのようなモノリシックなフレームワークを用いている場合、デフォルトでCSRF対策が入っている(ことが多い)ためCSRFの考慮する必要はないが、 React + RailsのようなSPA環境では、CSRF対策に関してもある程度自分で手を加える必要がある。 試しにやってみたので、軽くメモ。 とりあえず動く程度のメモなので、セキュリティ的に色々不都合はあるかもしれない。今後要調査。

やったこと

API

(準備) - CSRF用の機能を有効化する - include ActionController::RequestForgeryProtection(in application_controller.rb) - apiモードだとデフォルトで含まれていない様子なので、includeが必要そう

(tokenの生成) - ログイン時/ログイン確認時に、csrf tokenを生成 & レスポンスヘッダ(X-CSRF-Token)にcsrf tokenを挿入 - form_authenticity_token(ActionController::RequestForgeryProtectionの機能)を利用 - corsの設定で、expose: ['X-CSRF-Token']を追加(X-CSRF-Tokenヘッダをexposeする)

(tokenのチェック) - RailsCSRF tokenの確認を有効にする。 - protect_from_forgery with: :exception(in application_controller.rb, ActionController::RequestForgeryProtectionの機能) - ログイン時 のみCSRF tokenの確認を無効化 - skip_before_action :verify_authenticity_token, only: :create - verify_authenticity_tokenはprotect_from_forgeryの中で利用されている

フロント側

  • ログイン成功時、ログイン確認成功時に、axiosのデフォルトヘッダー(x-csrf-token)にAPIから受け取ったcsrf tokenを設定

実装例(github)

csrf api側 · takahiromasui001/spa_session_cookie_auth_trial@9c4017a · GitHub

csrf front側 · takahiromasui001/spa_session_cookie_auth_trial@5ee4a48 · GitHub

備考

  • 調査に時間はかかったが、実装はかなりシンプルになった。
  • セッション作成&セッションの確認毎にcsrf tokenを更新している。その点ではやや妥協。
  • ログイン時のcsrfも考慮していない。この辺りは今後の要改善点

参考にした情報

RailsのCSRF保護を詳しく調べてみた(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社 Railsそのもののtoken機能に関する詳しい説明。

Rails API mode+deviseなSPAでtokenによるCSRF対策をする - Qiita
方針の説明含め一番わかりやすい。サンプルコードもあり。 だいたいこれをパクった。

Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series
OWASPのCSRFに関する説明および対策を解説した資料。一通り目を通すだけでもCSRFの概略は掴める。 今回の実装ではここで示されている、synchronizer token pattern(を少し簡略化したもの)を採用

RailsでCORSのAccess-Control-Expose-Headersを設定する - Qiita
Rails APIにCORSアクセスした場合は、reseponseのヘッダーに表示する情報をあらかじめ設定しておく必要がある、という話。

AjaxにおけるCSRF攻撃対策 - バカンス駆動開発
Twitterのソース(?)をみた話とかが書いてある。csrf tokenはセッション単位で発行しているらしい。本記事もこれに倣った。

Rails(API)でcookieを使ったログイン機能実装のメモ

Rails(API)でcookieを使ったログイン機能実装」にあたり、微妙に引っかかった点のメモ。 人が読むことを全く意識していない。

Userモデル作成

bin/rails g model user name:string email:string password_digest:string

has_secure_password

  • Userモデルにhas_secure_password追加
  • gemfileにbcrypt

sessions_controller: login(create)

ローカル環境(localhost)におけるRails APIのhttps対応 & Chromeデフォルト環境でエラーなく動作するための証明書作成

「ローカルの開発環境(localhost)でRails APIhttps化」してみたので手順を残す。 (正直勘違いからのスタートだったので、用途を言及できないが。。。)

Railshttps化

基本的に以下の記事をそのまま利用。記事の実装は開発環境のみで動く形になっているので、本番環境以降時に変な影響を受けることがないのが安心ポイント

Railsの開発環境でhttpsを使う - Qiita

自己署名証明書の作成

上で作成した証明書は、このままだとブラウザから見て信頼できないものになるので、Chromeでエラー(ERR_CERT_AUTHORITY_INVALID)が発生する。そのためオレオレ証明書を作成しブラウザにインポートする必要がある。 またChromeの場合、ドメイン名のチェックをCommon Name(通称CN)ではなくSubject Alternative Names(通称SAN)を参考するようになったため、 SANが含まれていない場合エラー(NET::ERR_CERT_COMMON_NAME_INVALID)が発生する。 そのためSubject Alternative Namesを含んだ自己署名サーバ証明書を利用する必要もある。

自己証明書の作成

Chromeで使えるオレオレ証明書を作成する方法 - Qiita
上の記事で紹介されているツール(self-sign-cert)を利用することで容易に署名付き証明書を作成できる(感謝)。

証明書のブラウザへのインポート

Google Chromeへ証明書ファイルをインポートするには | サポート・お申し込みガイド | GMOグローバルサイン【公式】

Mac端末での手順

作成した証明書を上の手順に従ってブラウザにインポートする。

Railsのデフォルトのcookieを用いたセッション管理における、セッション情報の保管場所について

Railsでセッション管理を行う場合は、"session"メソッドを利用するのが基本になる。 Railsのデフォルト動作ではこの"session"メソッドを用いた際cookieを用いてセッション情報を管理する事は知っていたが、 具体的に何をしているかに関してはあまりよく理解していなかった。

調査をしてみてある程度理解できたので備忘録代わりに記載する。

概要

  • セッション情報はcookieに(暗号化の上で)埋め込まれて各クライアント(ブラウザ)で保持される
  • サーバ側ではセッションに関する情報は一切保持していない (セッション情報の作成(?)や暗号化はする)

らしい。(多分合ってる)

参考にしたサイト

https://railsguides.jp/security.html#%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8
https://oauth.jp/blog/2013/09/26/rails-session-cookie/
https://www.slideshare.net/carotene4035/sessionrailscookie-store

備考

セッションってサーバー側で保持されるようなイメージだったが、cookieってクライアント側で保持するよなぁという点がいまいち納得できていなかった。 cookieに入れる情報の作成&暗号化及び復号はサーバー(Rails)側で行うためセッション情報を管理しているのはサーバ側と表現するのも間違っていないかもしれない。 ただセッション情報の保管はクライアントがcookieを所持する形で行なっているということになるのかね。