
2025.08.01
災害大国・日本に求められる“命しか守れない防災”からの脱却 最長2週間先の気象災害予測による対応策
Rails APIモードにおけるToken認証機能について(全1記事)
リンクをコピー
記事をブックマーク
越川佳祐氏:私からは、「Rails APIモードにおけるToken認証機能について」というテーマでLT(ライトニングトーク)をしようと思っていたんですが、スライドを作っていて「あれ、これ別にRailsだけの話じゃなくない?」と思ってしまいました。みなさんの中にも、そう思う方がいるかもしれないんですが、もうこれで作っちゃったのでご了承ください。
私は株式会社iCAREで、サーバーサイドエンジニアをしている、越川と申します。Twitterは@kossy0701という名前でやっているので、よければフォローをしてもらえればと思います。
突然なんですが、みなさんこんな経験はありませんか? 「Rails APIモードで何か開発したいな、認証機能どうしようかな、devise_token_authというトークンベースの認証方式を提供するGemがあるのか。CORSという仕組みの設定が必要なのか。rack-corsというGemなら簡単にCORSの設定ができるのか。rails g devise_token_auth:install User authすれば簡単に導入できるのか。Postmanを使えば普通にAPIのテストもできるのか……」という流れを、僕も何回か経験しているんですが、APIモードだとCookieの仕組みがデフォルトで入っていないので、デバイスじゃなくてdevise_token_authというGemを使うことがけっこう多いのかなと思っています。
あとはCross-Origin Resource Sharingなんですが、これも例えばRailsをlocalhost:3000で、Vueをlocalhost:8080でと2つサーバーを立ち上げて試すというときは、異なるオリジンで通信する必要があるので、CORSの設定をrack-corsでやることがけっこう多いんじゃないかなと思っています。
Postmanは無料で試せるAPIのクライアントですね。これも便利なのでみなさん使ってみてください。ここで矢印が終わっているんですが、認証用のトークンはどこに保存すればいいの? という疑問にたどり着くんですね。
僕もたどり着いたので、今回「SPAの認証Tokenどこに保存するの問題」を話していきたいと思います。これは別にRailsと関係はなくない? といったところなんですが、すみません、ここはご了承ください。
認証トークンの保存先として、ローカルストレージと、Cookieと、インメモリがよく挙がる名前だと思っています。順に上から説明していきます。
選択肢その1として、ローカルストレージに保存するというシナリオですね。この場合は個人的には実装が簡単だと思っています。これはdevise_token_authの例ですが、ログインのAPIを叩いたら、ヘッダーの中にアクセストークンやuidやclientが入っていて、その中からローカルストレージにsetItemでゴリゴリ入れていきます。
認証が必要なエンドポイントを叩くときに、リクエストヘッダーにgetItemでトークンを取り出して、乗せて、リクエストするだけです。ログアウトするときはローカルストレージに入れていたトークンをremoveItemでそのまま削除すればOKで、ログアウトした後に、ログインページに遷移させるというフローだと思うんです。
最低限で実現するんだったら、これだけでいいのかなと思うんですが、みなさんご存知かもしれませんが、クロスサイトスクリプティングがあった場合、JavaScriptで操作しているものなので、トークンを簡単に盗めるんですね。
Auth0という認証プラットフォームの会社が、CDN経由にJavaScriptの脆弱性があってこれが盗めてしまうとドキュメントを出していて、わりと有名な問題です。
なので、例えばどうしてもローカルストレージに保存しなきゃいけないときは、トークンの有効期限そのものをかなり短くしたり、devise_token_authでリクエストごとにトークンを更新したり、XSSがあることを前提に認証まわりの実装をするのがいいんじゃないかなと思っています。
次はCookieですね。選択肢その2のCookieに保存するというものです。CookieにHttpOnly属性というものがあって、これをfalseにするとJavaScriptから操作ができます。これをtrueにしておくことで、JavaScriptからのCookie操作を無効にできるのでローカルストレージよりセキュアです。
ローカルストレージは、JavaScriptでゴリゴリ操作できちゃうので、そういう意味では(Cookieへの保存は)セキュアかなとは思っているんですが、これも懸念点はあります。セキュリティでかなり有名な徳丸浩さんが、「HttpOnly属性を仮にtrueにしていても、クロスサイトスクリプティングの脆弱性があるとcookieは盗めませんが、他の方法により攻撃ができる」ということを言及していました。
クロスサイトスクリプティング対策として、CookieのHttpOnly属性がどこまで安全になるのかですね。徳丸さんがCross-Origin Resource Sharingの話をしている動画があるので、ご覧いただければと思います。
(編注;スライドは発表当時のものであり、徳丸氏の発言とは異なります。)
選択肢その3のインメモリで保存する方法ですね。インメモリは何かというと、JavaScriptでブラウザのメモリ内に認証トークンを保存するというやり方です。例えばクロージャーみたいなものを作ってそこに入れるなど、やり方がいろいろとあって、これだと攻撃者からはどこにトークンが存在するかがわからないので、攻撃が困難だと言われています。
これも一見セキュアですが、懸念はあります。メモリ内にトークンを保存するので、例えばリロードするとログアウトされちゃうという問題です。ほかにも、ブラウザで新しいタブで開いたときに認証状態が継続されなくて、タブ間でもログイン状態が続かないので永続性がない、ログアウト状態になってしまうという問題があります。
3つともダメやんと思うかもしれませんが、ここで選択肢その4が出てきます。先ほどチラッとお話ししたんですが、Auth0という認証プラットフォームです。アメリカの会社なんですが、Webアプリやモバイル向け、API向けの認証や認可の仕組みを提供している、いわゆるIDaaSのプラットフォームです。誤解を恐れずに言うと、自前で認証認可の仕組みを実装したくない人向けのものだと思っています。
オプションで、2段階認証やSAMLの認証も提供しているのでけっこう便利なんじゃないかなと思っています。Auth0の何がいいのかと言うと、Silent Authenticationという仕組みがあって、インメモリ形式で実装しているんですが、リロード時にログアウトしてしまう問題がないのが利点として挙げられます。
これがAuth0のドキュメントで、『Configure Silent Authentication』とドキュメントがあるので、興味があればぜひ読んでいただきたいと思います。
どういう中身の実装になっているのかというと、HTMLの<iframe>というタグを酷使して、Silent Authenticationを実現しています。/auth0-spa-jsというGitHubのリポジトリ(https://github.com/auth0/auth0-spa-js)があって、僕もそれをがんばって読もうとして挫折したんですが(笑)。
興味がある人は、GitHubにオープンソースとして公開されているので、実装を確認してもらえればと思います。Auth0は、ドキュメントも充実していて、例えばこれはRailsの6でAuth0を使って認証APIを作るみたいなハンズオンなんですが、これもドキュメントがあります。ほかにも、フロント側もQuickStart Vue:Loginという、最低限こう実装すればできるみたいなチュートリアルも用意されていたり、スライドには書いていないんですが、モバイルアプリ向けのドキュメントも充実しています。
ここで懸念の話なんですが、これはセキュリティの話から離れてしまって恐縮なんですが、認証基盤のロックインという問題はあると思っています。例えば、Auth0がいいなと思って使い始めて、ユーザー数が増えてきたからコスト的にもキツイな、やめたいなとな、移行したいな、となったときに、その移行作業が大変だったり、単純にAuth0のサービスが停止してしまうというリスクもあると思うので、そういったところでAuth0だけに頼るのも難しいのかなと思っています。あとは、ユーザー数が一定数を超えると課金が発生するので、SNSなどで広がってユーザーが1万人とかになってくると、けっこう大変なんじゃないかなと思っています。
これがプライシングの画像なんですが、ここにも書いてあるとおり、5,000人のユーザーで114ドル/マンスリーの料金プランとなっているので、個人開発などであまりユーザーが増えないならいいかなと思います。が、Auth0は採用する前に、どれぐらいユーザー数が増えて、将来これぐらいのコストがかかるというところまで考えるべきだと思っています。
結局認証トークンをどこに保存するかは、アプリで扱う情報の機微性に応じて保管場所を決めるべきというありきたりな結論になってしまったんですけど(笑)。
例えば社内の書籍管理アプリみたいな最悪外部に出てもいいぐらいのレベル感だったら、ローカルストレージに保存してもいいと思うんですが、堅牢情報や決済情報など機密性の高い情報を扱うのであれば、セキュアな認証方式や認証トークンの保存場所を考える必要があると思っています。
ご清聴ありがとうございました。
※[編注]登壇者の要望を受け、一部加筆修正を行いました。(2021年5月21日 17:30)
誤)徳丸浩さんが、HttpOnly属性を仮にtrueにしていても、クロスサイトスクリプティングの脆弱性があると、XMLHttpRequestの実行でそのCookie内のトークンを盗むことができてしまうということを言及していました。
↓
正)徳丸浩さんが、「HttpOnly属性を仮にtrueにしていても、クロスサイトスクリプティングの脆弱性があると、cookieは盗めませんが、他の方法により攻撃ができる」ということを言及していました。
続きを読むには会員登録
(無料)が必要です。
会員登録していただくと、すべての記事が制限なく閲覧でき、
スピーカーフォローや記事のブックマークなど、便利な機能がご利用いただけます。
すでに会員の方はこちらからログイン
名刺アプリ「Eight」をご利用中の方は
こちらを読み込むだけで、すぐに記事が読めます!
スマホで読み込んで
ログインまたは登録作業をスキップ
2025.09.08
部下が不幸になる上司のNG行動5選 マネジメントは「自律と統制」のバランスでうまくいく
2025.09.10
人生の差は20代で決まる “指示待ち人間”で終わらないために積むべき4つの経験
2025.09.16
日本人が英語学習で苦戦する根本的原因 「言いたいことの順番」が真逆になる英語と日本語
2025.09.10
「やりたいこと」はないが「課題解決」自体を楽しめる人 Googleの「優秀なエンジニア」の定義
2025.09.04
「管理職になりたくない問題」の原因は上司にもある 部下の昇進意欲を削ぐ行動
2025.09.16
“できる仕事のキャパが10倍になった” 東証上場社長を変えた習慣「ピッパの法則」の効果
2025.09.11
自分の得意・不得意がわかるワーク 人生を再設計する「ライフキャリア」の見つけ方
2025.09.17
英語ネイティブは「would」をどう使っているか? 「Do you like〜」と「Would you like〜」の違い
2025.09.12
“起業が向いている人”と”経営が向いている人”は違う DMM亀山会長が語る、新規事業の生み出し方
2025.09.09
“指示待ち社員”から「自分で考え、動く社員」に育てる方法 セルフリーダーシップの発揮に重要な3つのアプローチ