7 ポイント 投稿者 GN⁺ 2024-10-11 | 1件のコメント | WhatsAppで共有
  • Webアプリケーションで 認証実装 を設計する際に参考にできる基本ガイドであり、オンラインの認証資料の空白を埋めることを目的としている
  • 無料・オープンソース の資料であり、コミュニティが保守する形で提供されている
  • 一部の内容は 意見が反映 されていたり不完全だったりする可能性があるため、単独の基準として使うより補助資料として活用するのが適切
  • 認証セキュリティの参考資料である OWASP Cheat Sheet Series とあわせて使うことを推奨
  • 提案や懸念事項は新しい Issue を作成して伝えることができ、文書改善に参加できる

文書の目的と性格

  • The Copenhagen Book は、Webアプリケーションで 認証(auth) を実装する際に参考にできる一般的なガイドラインを提供する
  • 運営形態は次のとおり
    • 無料で提供される
    • オープンソースである
    • コミュニティが保守する
  • 内容はときに意見が反映されていたり、完全ではなかったりすることがある

あわせて参考にする資料と参加方法

  • 認証実装時には OWASP Cheat Sheet Series とあわせて参照することを推奨
  • 提案や懸念事項があれば、新しい Issue を作成できる

1件のコメント

 
GN⁺ 2024-10-11
Hacker News のコメント
  • 勘違いでなければ、この記事は TypeScript 向けの人気認証ライブラリ Lucia の作者が書いたものらしい
    最近、Lucia ライブラリはもはや認証実装における人間工学的な方法ではないと判断し、ライブラリを廃止して文章によるガイドシリーズに置き換えると発表した
    初期のガイドのプレビューは読みやすく、The Copenhagen Book ともよく合っていた
    https://github.com/lucia-auth/lucia
    https://github.com/lucia-auth/lucia/discussions/1707
    https://lucia-next.pages.dev/

    • なぜそう判断したのか文章にまとめているのか気になっていたが、ここにあった: https://github.com/lucia-auth/lucia/discussions/1707
      複雑さが爆発しそうな兆候を見て、ライブラリが本人にとってももはや有用ではないことを認めたうえで、ありがちな ライブラリ肥大化 の標準的な道筋から謙虚に降りた点は珍しい
    • それでも Lucia はすぐ別の人気 認証ライブラリ に置き換えられる可能性が高い
      実際、99% の人に必要なのはログイン/ログアウトだけで、これはライブラリとして提供されると非常に便利だ
      Web 8.0 のパスキーを WASM 楕円曲線ソケットで提供しなければならないなら、自作するか Auth0 を使えばいいだろうが、CRUD 料理アプリを作っている人に OAuth 仕様と落とし穴リストを投げて認証を自作しろと言うのはおかしい
      その人は配管を再発明するより実際のアイデアに集中すべきで、多くの人が結局誤って実装し、事実上認証がない状態になりかねない
  • この部分は間違っている: 「メールアドレスは大文字小文字を区別しない」
    https://thecopenhagenbook.com/email-verification
    メール標準によれば メールアドレスは大文字小文字を区別する
    送信過程でメールアドレスを小文字化すると、別の人にメールが届く可能性があり、認証では危険だ
    多くの有名メールプロバイダーは大文字小文字を区別しないことを選んでいるが、一般的な認証を扱うサイトなら一般的なケースを推奨すべきだ
    https://stackoverflow.com/questions/9807909/are-email-addres...
    付け加えると、ある文字の反対の大文字・小文字が何なのかは常に明確とは限らず、時間とともに変わることもある。たとえばドイツ語の大文字 ß は 2008 年に Unicode に追加されたので、一般的なプログラミングでは可能なら大文字小文字の区別を避けるほうがよい

    • リンク先の Stack Overflow の最上位回答は、むしろ逆のことを言っている: 「実際には、広く使われているメールシステムの中で大文字小文字で別のアドレスを区別するものはない」
      標準は一つのことを言っているが実装は違う動きをしており、この場合、標準の文言だけに従うと現実世界で問題が起きる
    • 私のやり方は、ユーザーが入力した 元の大文字小文字 を保存しつつ、検索は大文字小文字を区別しないようにすることだ
      こうすればメールは最初に入力された大文字小文字のアドレスに送り、ログインは大文字小文字に関係なく可能になる
      欠点は、大文字小文字だけが異なるメールアドレスを持つ 2 人のユーザーを別々に置けないことだが、その程度は問題ないと思う
    • メールで登録すると、そのメールアドレスがログイン用ユーザー名になる場合があった
      メールアドレスは大文字小文字を区別しなかったが、メールから作られた ユーザー名は大文字小文字を区別 していたため、大文字を含むメールアドレスでアカウントを作ると、その大文字小文字どおりに入力しないとログインできず、大文字小文字を無視したメールアドレスではログインできなかった
    • 大文字そのものをなくしてしまおう。無駄が大きすぎる。次はタイムゾーンで、UTC 万歳だ
      その次には言語と文化の違いもなくせば、何十億行ものコードが消えるはずだから、リポジトリがもう縮んでいく音が聞こえる
    • 理論的には正しいが、実際には初期実装のバグのせいで、同じメールアドレスが複数の大文字小文字パターンで保存されているシステムを何度も見た
      たとえば、あるユーザー項目には JohnDoe@example.com、別の項目には johndoe@example.com が入っていて、明らかに同一人物というケースだ
      しかも別々のシステムから入ってきた値だったので、さらに厄介だった
      大文字小文字を区別しないメールアドレスのリスク行列のほうが、大文字小文字を区別するメールアドレスよりはるかにましだと思う。つまり、すべてのメールアドレスを小文字に変換するほうが正しく、The Copenhagen Book もこの点では正しい
  • とても良い。セキュリティ資料の 90% は、セキュリティ専門家でなければ到底理解できないように作られているように感じて、いつも不満だった。特に 暗号学の資料 がそうだ
    だが、ここのほぼすべてのページは明確で、簡潔で、要点を突いており、すぐ適用できるので気に入っている
    ただし楕円曲線のページは、他の暗号学資料と同じくらい理解しにくかった

    • 暗号学が難解な理由を短く言うと、暗号学は 数論 と N!=NP という計算量理論上の仮定、つまり一方向関数/トラップドア関数が存在するという仮定に依存している
      動作原理そのものが数学なので、本質的に不透明だと思う
      有限体や楕円曲線、実質的には整数群を理解してから、多くの暗号学を把握できるようになり、たいていは何らかの形で 離散対数問題 だった
  • 似たテーマの代替ドキュメントもあるとよい。たとえば OWASP Cheatsheet のようなものだが、より実用的な観点のドキュメントのこと
    敬意は払うが、この文書には少し懐疑的
    名前がかなり大げさだ。まるでコペンハーゲンの大学研究者たちが書いたかのように文書を呼ぶのは、見事なマーケティング上の小技だ
    Lucia が比較的人気のあるライブラリなのは確かだが、だからといってベストプラクティスを推進しているとか、著者をこの重要分野の権威と見るべきだという意味ではない
    Lucia の設計で気に入らない部分もある。ユーザートークンがほぼ期限切れになるとき、新しいセキュリティトークンを作るのではなく、既存トークンの寿命を延長するよう提案している
    トークンが事実上永遠に生き続け、悪用され続け得るので、非常に安全でない挙動に見えるし、制限されたトークン寿命というセキュリティのベストプラクティスに反している
    Lucia と “Copenhagen Book” はどちらもこの方式を推奨している: https://thecopenhagenbook.com/sessions#session-lifetime

    • 投稿されたリンクのコードはトークンの寿命を「延長」するのではなく、セッションを延長するコードに見える
      これはよくある方式で、通常はローリングセッションと呼ばれる
      トークン自体はそもそも不変であるべきなので寿命を変更できるべきではなく、そのためトークンの更新は元のトークンを変えるのではなく、新しいトークンを渡す方式になる
    • トークンを破棄し、新しいトークンを含めてクライアントに応答したのに、クライアントがすでに以前のトークンで新しいリクエストを送っていた場合、そのリクエストは拒否される
    • Lucia の文脈では、既存セッションを延長することと新しいセッションを作ることの間に違いはないと思う
      1つ目の場合、攻撃者はトークンを盗んで永遠に使う。2つ目の場合でも、攻撃者がトークンを盗んだあと、期限切れ直前に新しいトークンを受け取れば、ユーザーになりすまし続けられる
      ユーザーが締め出されれば何かに気づくかもしれないが可能性は低く、良いユーザー体験のためにはどうせ猶予期間が必要になる。そうしないと並列リクエストで正当なユーザーにも問題が起きる
      2つ目のトークン、つまりリフレッシュトークンを使うことはできるが、リスクをそのトークンへ移すだけだ。今度はリフレッシュトークンが盗まれて永遠に悪用されることを心配しなければならない
      リフレッシュトークンは、リクエストごとにデータベースを叩かなくてよい点で有用だ。通常、短命のセッショントークンは署名付き JWT のようにデータベースなしで検証できる
      ただし盗難時に無効化できず、有効期限までは有効なので、被害を抑えるには期限を短くする必要がある
      一方、リフレッシュトークンではデータベースを参照する。2つ目のトークンそのものがセキュリティを加えるのではなく、データベース参照がセキュリティを加える。データベースから削除して無効化できるからだ
      Lucia は少なくとも例を見る限り常にデータベースを参照するので、いつでもトークンを無効化できる
      リスクを減らすには、ユーザーがアクティブなセッションを見て終了できるようにすべきだ。可能なら時刻、場所、デバイス情報も一緒に表示するとよい。例: “昨日午前12時にコペンハーゲンの iPhone からログイン”
      新しい場所やデバイスからログインしたらユーザーに通知することもできる
      結局、長期間続くセッションを完全に安全に実装する方法はない
    • 名前にあまり多くの意味を持たせすぎているように思う。ただしセッショントークンのローテーションの代替方式には興味がある
      良い指摘だと思うが、自分が専門家だとは言えない
  • OAuth で誰もが見落としていて、あまり表に出てこないことが2つある
    そのうち1つを誰かが指摘してくれてうれしい。トークンを使うときは、トランザクションを分散ロックメカニズムとして必ず使うべきだ
    リフレッシュトークンではこの重要性が2倍、4倍になる。同じトークンを2回以上使うと、そのユーザーはログアウトされる
    システムが1台で動いていようが N 台で動いていようが関係ない。リフレッシュトークン付きのリクエストが2つ以上同時に進行していると、これは非常によく起きるのだが、ユーザーをログアウトさせ、しばしば 500 で終わる
    リフレッシュトークンは使い捨てだ
    開発者と認証フレームワークが見落としているもう1つは “state” パラメータだ

    • ネットワーク上に「一回限り」は存在しない。サーバーがリフレッシュトークンを受け取った瞬間にただちに無効化するのは、自ら問題を招く行為だ
    • 複雑すぎるし、日常的な認証には向いていないと思う
      最近の認証が全体として進んでいる方向を見ると、曖昧さによるセキュリティではなく、曖昧さによる不安定性に近づいているように思える
      アプリケーション状態まで絡むと、認証に合わせてアプリケーションロジックを調整しなければならず、誰かがリフレッシュトークンを盗んだかどうかをアプリケーションが確認しなければならない
    • 同じような理由で、ほとんどのシステムはリフレッシュトークン再利用の猶予期間を実装している
      トランザクションだけでは解決しない。たとえばタブを2つ素早く開くと、元のリフレッシュトークンでサーバーを2回叩くことになる
    • OAuth Threat Model 文書を知っている可能性が高い
      その文書ではリフレッシュトークンのローテーションを好ましいとしているが、クラスター環境での明らかな難しさにも触れている: https://datatracker.ietf.org/doc/html/rfc6819#section-5.2.2....
    • すみませんが、実際のアプリケーションではそうは動かない
      複数のリクエストは常に同時に発生する。たとえばブラウザが複数タブで起動したり、スマートフォンアプリが起動時に複数のリクエストをまとめて送ったりすることはよくある
  • もっと多くのウェブサイトに「ログアウトするまでセッションを期限切れにしないでほしい。リスクは理解している」という選択肢を用意してほしい
    最近の「remember me」ボタンは何の効果もない
    セッション期限切れのせいで一日が何度も中断されるのにはうんざり。GitHubは特に嫌いで、週1回ほど使うだけなのでセッションがいつも期限切れになっており、二要素認証まで強制されるため、毎回スマホを取り出して数字を入力しなければならない
    ユーザー体験もひどいが、根拠はないにせよ、こうして何度もログインさせるとユーザーが疲れて注意力が落ちると思う
    あるサイトに毎週何度もログインしていると、60回目くらいのログインではフィッシングサイトが紛れ込みやすくなる。逆に、ほとんどログインすることのないアカウントが突然パスワードを要求してきたら、不自然に感じて警戒心が高まる
    結局、企業は人によってリスク許容度やセキュリティ態勢が違うことを学び、選択肢を提供すべき
    付け加えると、GitHubの頻繁なセッション期限切れと二要素認証があまりに鬱陶しかったので、Giteaに移行して期限切れをオフにしてしまった。移行理由の90%はそれだった
    自分のネットワークからしかアクセスできないので、むしろセキュリティは良くなったと感じている。柔軟性のないセキュリティモデルのせいで企業が顧客を失うことは十分あり得る

    • この資料にはセッション寿命をどう扱うべきかについて良い推奨がある
      ざっくり言うと、30日以内に使われていればセッションをさらに30日延長する方式
      https://thecopenhagenbook.com/sessions#session-lifetime
    • 自分にとってはNotionが最悪。頻度の問題ではなく、アクティブなセッションを実際に切って再ログインさせるから
      さらに悪いのは、セッションが1週間より1〜2分ほど長く続くように見えるため、今週は先週の作業を始めた直後に追い出されることになる点
      数週間前、定例会議の直前にメモを取ろうとしてログインしたのだが、その後数週連続でその会議の途中にログインを強制された
    • ブラウザ設定で何か変えていないか確認してみる必要がある
      そうした「remember me」ボタンを無効化し得る設定は非常に多い
      個人的にはGitHubを含め、ウェブサイトのログイン維持で問題が起きたことはない
    • 一部の認証プロバイダーは料金プランに応じてトークン寿命を制限している
    • 少なくともセキュリティ劇場は楽しめる
  • 最近SRPプロトコルを知ったが、もっと広く使われたり言及されたりしていないのが驚き
    比較的シンプルなプロトコルでゼロ知識証明を行い、サーバーとクライアント間のセッショントークンまで一度に作れる
    https://en.wikipedia.org/wiki/Secure_Remote_Password_protoco...

    • 特許のせいで導入が妨げられていた
  • この資料は気に入った。多くのセキュリティ助言は難解で、ときにはばかげているようにも感じる。まるで何もするなと助言する弁護士のようだ
    このガイドは驚くほど簡潔で、追いやすく、理解しやすく、率直な助言があるのが良い
    反対意見や注意点があるかコメントを見続けるつもりだが、自分の認証プロジェクトと照らし合わせて検討することになりそう
    ひとつ望むなら、JWTセクションがあればよかった。著者の意見が「使うな」なら、そう言うだけでもよい

    • 「何もするなと助言する弁護士のようだ」という表現はしっくり来る
      セキュリティ担当チームについてよく批判する点のひとつは、人々がやりたいことを効率的にできるツールや方法を先回りして提供するよりも、してはいけないことを伝えるのに多くの時間を費やしていること
    • SAMLセクションと、実装方法に関する高レベルの概要もあるといい
    • メール確認やパスワードリセットのようなメールフローは、秘密トークンが十分に強いなら数日間有効にしておくことを勧める
      メールはより安全なシステムと見なせるので、即時に、あるいはどこからでもアクセスできるとは限らない
  • ここでいう「auth」は認証(authn)を指すのか、認可(authz)を指すのか気になる
    見たところ認証を指しているようだが、明確にしてくれるとよい

    • セッショントークン、パスワード、WebAuthnを扱っているので、両方を含んでいるように見える
  • 少し関連した短い愚痴だが、内蔵ブラウザがウェブを台無しにしている
    内蔵ブラウザはソーシャルOAuthの利用を不可能にする。場合によっては文字どおり不可能で、別の場合には事実上不可能
    InstagramでリンクをタップするとデフォルトでInstagramブラウザで開くが、そのリンクに「Sign in with Google」があると、GoogleがInstagramのような「安全でないブラウザ」をブロックするため動作しない
    「Sign in with Facebook」すら問題が起きる。MetaはInstagramとFacebookの両方を所有しているのに。Facebookの内蔵ブラウザでも似た問題がある

    • 内蔵ブラウザには良い用途がたくさんあるが、任意のリンクへ移動することはそのひとつではない
      Slackのような場所でリンクをタップした後にメッセージに返信し、またブラウザに戻ってそのページがあることを期待したのに、Slackが自分のブラウザ内に飲み込んでしまってどこにもない、という場合はほぼ常に役に立たない
      幸い、今確認したところSlackでは内蔵ブラウザをオフにする方法がある