2024.10.01
自社の社内情報を未来の“ゴミ”にしないための備え 「情報量が多すぎる」時代がもたらす課題とは?
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.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには