セキュリティ

アプリを非公開に、別々に保つしくみ

作る人がこれを書く必要はありません。ログイン、社内限定のアクセス、アプリごとのデータの分離、検索エンジンに載せないことは、最初のデプロイの時点ですべてのアプリに備わります。ここでは、承認する立場の方のために具体的に説明します。TeamOnly はアーリーアクセス中です。このページは現在の構成と運用を説明しており、変更があれば正確に更新します。取得していない認証を取得済みと主張することはありません。

すべてのリクエストは、まずログインから

*.teamonly.app へのアプリのトラフィックは、すべて最初に1つのディスパッチ Worker に届きます。ここでホスト名から組織とアプリを特定し、有効なセッションがあるかを確認してから、リクエストをアプリに転送します。セッションがなければ、訪問者にはログイン画面が表示されます。その人に対して顧客のコードが動くことはありません。

ログイン方法は3つです。Google の OpenID Connect、Microsoft(Entra ID)の OpenID Connect、または会社のメールアドレスに送るワンタイムコード。Google と Microsoft では、ID トークンを私たちのサーバーで検証します。署名、audience、有効期限、メールのドメインまで確認します。Google の hd の値は、リクエストのものを信用せず、検証済みのトークンから確認します。Microsoft では職場または学校のアカウントのみを受け付け、トークンの issuer がそのテナント自身と一致する必要があります。

メールのコード

Google や Microsoft の代わりに、同僚は会社のアドレスで6桁のコードを受け取ることもできます。Google Workspace や Microsoft 365 を使っていない会社は、この方法で設定なしに TeamOnly を使えます。コードは、その人が御社のドメインのメールボックスを使えることを証明します。これは Google や Microsoft のログインが証明するものと同じです。どのメールサービスでも使えます。Gmail や Outlook.com などの個人アドレスは、会社のアプリでは受け付けません。

  • コードは10分で失効します。
  • 5回間違えるとコードは使えなくなり、新しいコードを要求する必要があります。
  • コードは要求したブラウザでしか使えません。肩越しに見られたコードや転送されたコードは、別のブラウザでは役に立ちません。
  • リクエストはメールアドレスごと、IP アドレスごとに回数を制限しているので、フォームを使って受信箱をあふれさせることはできません。
  • フォームは Cloudflare Turnstile で保護され、スクリプトではなく人が要求していることを確認します。
  • フォームは、そのアドレスがログインできるかどうかにかかわらず同じ応答を返すので、誰がアクセスできるかは明かしません。
  • コードは signin@teamonly.app から送信され、SPF、DKIM、DMARC を設定しているので、メールサービス側で本当に私たちから届いたものか確認できます。
  • コードはハッシュとしてのみ保存し、その間に変更があった場合に備えて、コードの入力時にもう一度アクセス権を確認します。

アプリが信頼できる身元情報

ディスパッチ Worker は、受け取ったリクエストの身元情報のヘッダーをすべて取り除いてから、確認済みのメールアドレスと名前を、そのアプリでのその人の役割と一緒に自ら設定します。SDK はそれを ctx.user としてアプリに渡します。

入口で
incoming request to expenses.acme.teamonly.appx-teamonly-user: ceo@acme.com    removed, not from usx-teamonly-user: dana@acme.com   added from verified sign-in
ヘッダー名は説明用の例です。アプリはヘッダーではなく SDK からユーザーを読み取ります。

アプリごとに別のデータベースとファイル保存

各アプリには、最初のデプロイで作られる専用の D1 データベースと、ファイル用の専用の R2 ストレージプレフィックスがあります。アプリに付くデータのバインディングはこれだけです。アプリは Workers for Platforms のディスパッチ名前空間の中で別々のスクリプトとして動き、互いのバインディングには届きません。

これは意図的にテストしています。あるアプリが別のアプリのデータ、Cookie、シークレットを読もうとするテストです。このテストは本番のプラットフォームに対して実施し、アプリを分離している部分に変更があるたびに再実施します。

3つの部屋がある間取り図: expenses、inventory、lookup のアプリ。各部屋には、それぞれのデータ、ファイル、シークレットがあります。expenses のアプリが inventory の部屋に手を伸ばそうとして、壁にぶつかります。inventory のアプリが lookup の部屋に手を伸ばそうとして、同じく壁にぶつかります。データ、Cookie、シークレットは、それぞれの部屋に留まります。

各アプリは自分の部屋にいます。データ、ファイル、Cookie、シークレットは中に留まります。

シークレットはコードの外に保存

シークレットは npx teamonly secrets set で設定し、そのアプリだけに付く暗号化された Worker シークレットとして保存します。リポジトリにもバンドルにも含まれず、ほかのアプリからは見えません。スキルファイルは、キーを決してコードに書かないよう AI に指示しています。

Cookie は1つのアプリのアドレスに限定

セッション Cookie は、expenses.acme.teamonly.app のようなアプリの正確なホスト名に対して、Secure、HttpOnly、SameSite 付きで設定します。teamonly.app や組織のサブドメインに設定することはないので、あるアプリが別のアプリのセッションを読むことはできません。

teamonly.app は現在 Public Suffix List に載っていないため、ブラウザは same-site の判定ですべてのアプリのアドレスを1つのサイトの一部として扱います。そのため、各セッション Cookie をアプリの正確なアドレスに固定しています。この状況が変わったら、このページでお知らせします。

顧客のコードは信頼しないものとして扱う

どのアプリにもミスや悪意のあるコードが含まれうると想定しています。一部は AI が書いたものであり、誰でも間違えるからです。だからこそ認証はアプリの外にあり、各アプリには自分のリソースしか与えず、アプリが何を送ってもログイン中の人が変わることはありません。アプリが社内の人にしか、しかも1時間に宛先100件、1日に500件までしかメールを送れないのも同じ理由です。

動いている場所

すべて Cloudflare 上で動いています。コードは Workers と Workers for Platforms、データベースは D1、ファイルは R2、セッションは KV です。自前のサーバーは運用していません。データ保存リージョンの選択は Business プランに含まれ、ご利用開始時に一緒に設定します。

一緒に設定するもの、決してしないこと

Business プランでは、IT部門と一緒に Okta などの SSO を設定します。監査ログとデータ保存リージョンも同じように一緒に設定します。どれもプランに含まれていますが、ご自身で切り替えるスイッチではありません。

  • 一緒に設定
    Okta、OneLogin などの SSO(Business プラン)
  • 一緒に設定
    監査ログ(Business プラン)
  • 一緒に設定
    データ保存リージョンの選択(Business プラン)
  • 決してしない
    認証なしの一般公開アプリ

現時点で SOC 2 や ISO の認証は取得していません。

セキュリティ上の問題の報告

件名に「Security」と入れて、hello@teamonly.dev までメールでお送りください。すべてのメッセージを人が読み、受け取ったことを返信でお知らせします。公表する前に、修正のための妥当な時間をいただけますようお願いします。

よくある質問

よくいただく質問

すべての質問と回答

あるアプリが別のアプリのデータベースを読めますか?

読めません。各アプリがアクセスできるのは、自分のデータベース、ファイル保存、シークレットだけです。ほかのアプリのリソースに対する認証情報もバインディングも持たないので、接続する手段がありません。

アプリが別のユーザーになりすますことはできますか?

アプリ自身に対しても、私たちに対してもできません。受け取ったリクエストの身元情報のヘッダーは入口で取り除かれ、確認済みのものに置き換えられるので、訪問者が別人を装うことはできません。アプリから見える身元は、必ず実際のログインに基づいています。

アプリが検索エンジンに登録されることはありますか?

ありません。すべてのアプリがログインの内側にあるので、クローラーがたどり着けるのはログイン画面だけです。そのログイン画面を含め、すべてのレスポンスで noindex を送っています。

アーリーアクセス

最初のツールを、今週公開しましょう。

TeamOnly はアーリーアクセス中で、すべてのプランを今すぐお申し込みいただけます。カード不要で14日間無料でお試しいただくか、お申し込みください。どちらの場合も御社の準備はすぐに整い、コマンド3つで最初のアプリが公開されます。

14日間無料で試すまたは今すぐ申し込む

トライアルはカード不要。その後は月額 $19 から、いつでも解約できます。

まだ検討中なら、最新情報を

会社のメールアドレスをお使いください。お知らせする価値のあるニュースがあるときだけ、たまにお送りします。

ご質問は hello@teamonly.dev へ。人が返信します。