2024.10.10
将来は卵1パックの価格が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は盗めませんが、他の方法により攻撃ができる」ということを言及していました。
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略