mcpField
M
meteor-security

meteor-security

github.com/meteorセキュリティ10295 回インストール5 日前に更新
リポジトリ

meteor-security について

Meteor 開発者向けのセキュリティガイドです。メソッドとパブリケーションのアクセス制御、コンテンツセキュリティポリシー、レート制限、OAuth シークレットの暗号化を扱います。

主な機能

  1. 01メソッド引数と認証状態の検証
  2. 02パブリケーションの絞り込みとフィールド投影
  3. 03CSP とブラウザーポリシーの設定
  4. 04機密性の高いメソッドのレート制限
  5. 05OAuth プロバイダーシークレットの暗号化

活用シーン

  1. 01メソッドとパブリケーションのアクセス制御監査
  2. 02機密データや無制限データの公開防止
  3. 03スクリプトやフレーミングへの対策
  4. 04ログインやパスワードリセット要求の制限

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/meteor/agent-skills --skill meteor-security

インストール後、Claude Code で/meteor-securityを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
browser-policy-csp.md
eval-cases.md
method-and-publish-guards.md

詳細

Meteor のセキュリティ

Meteor のセキュリティモデルには明確な方針があります。権限を持つのはサーバーであり、クライアントは信頼できません。ユーザーにデータが届く前にフィルタリングする場所は、メソッド(書き込み経路)とパブリケーション(読み取り経路)だけです。

判断フロー

  1. すべてのメソッドを監査します。すべての引数に対して check() を実行し、認証が必要な場合は this.userId または Meteor.userId() でガードしていますか?
  2. すべてのパブリケーションを監査します。ユーザー固有のデータの場合、this.userId でフィルタリングし、fields で列を投影していますか?
  3. 開発環境に audit-argument-checks を追加して、check() の不足を検出します。
  4. browser-policy を追加して、CSP を設定します。
  5. ログイン、パスワードリセット、リソース作成などの機密性の高いメソッドに DDPRateLimiter ルールを追加します。
  6. アプリで OAuth を使用する場合は、プロバイダーのシークレットを保存時に暗号化するため、oauthSecretKey を設定します。
  7. 制限の緩いクライアント書き込みルールを、認証済みメソッドに置き換えます。同等のメソッドのみのポリシーが有効になるまでは、保護用の deny ルールを維持してください。Accounts は、アプリの allow ルールがなくても、所有者のみが対象となる profile の許可を追加できます。以下の profile ポリシーを参照してください。

Accounts コレクションと profile ポリシー

Meteor 3.6 で修正された Accounts の連携では、カスタムのユーザーコレクションにアカウント用のインデックスが追加され、クライアントの変更メソッドが存在する場合は、デフォルトで所有者のみを対象とする profile の許可も追加されます。ガードを設定する前に、両方のランタイムでコレクションを設定してください。すべてのクライアントによる profile の書き込みをブロックする必要がある場合は、同等のポリシーが実証されるまで、選択したコレクションに Meteor.users.deny({ update: () => true }) を維持してください。defineMutationMethods: false を指定すると、これらのバリデーターを持たないメソッドのみのコレクションになります。RC でもアカウント用のインデックスは作成されます。それ以前のパッケージでは、セットアップ時の動作を確認する必要があります。コレクションの識別、セカンダリ Accounts インスタンス、パッケージの境界については meteor-accounts を参照してください。クライアントが編集できる profile に保存されたロールは、決して信頼しないでください。

メソッドのガードチェックリスト

import { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";

Meteor.methods({
  async updateProfile(payload) {
    check(payload, { displayName: String, bio: Match.Optional(String) });
    if (!this.userId) {
      throw new Meteor.Error("not-authorized");
    }
    await Meteor.users.updateAsync(this.userId, { $set: { profile: payload } });
  },
  async updateAddress(payload) {
    check(payload, String);
    if (!Meteor.userId()) {
      throw new Meteor.Error("not-authorized");
    }
    await Meteor.users.updateAsync(Meteor.userId(), { $set: { address: payload } });
  },
});

次の条件に一致しないメソッドは拒否してください。すべての引数で check を実行すること、必要に応じて userId でゲートすること、エラー時に Meteor.Error(code, reason) を使用すること、サーバーでは *Async の Mongo を使用すること。

パブリケーションのガードチェックリスト

Meteor.publish("items.mine", function () {
  if (!this.userId) return this.ready();
  return Items.find(
    { ownerId: this.userId },
    { fields: { title: 1, qty: 1 }, limit: 200 },
  );
});

上限のないカーソルを返す、フィールドの投影を省略する、またはユーザー固有のデータに対する userId のフィルターを省略するパブリケーションは拒否してください。

browser-policy による CSP

meteor add browser-policy
// server top-level or inside Meteor.startup
import { BrowserPolicy } from "meteor/browser-policy-common";
import { Meteor } from "meteor/meteor";

Meteor.startup(async () => {
  await BrowserPolicy.content.disallowInlineScripts();
  BrowserPolicy.content.disallowEval();
  BrowserPolicy.framing.disallow();
});

BrowserPolicy はサーバー専用です。すべてのリクエストに対して、プロセス全体で一貫したポリシーが適用されるよう、モジュールの初期化時または起動時に設定してください。現在の実装では、ポリシーの変更後にキャッシュされた CSP が無効になりますが、このグローバルポリシーをリクエストごと、またはユーザーごとに変更しないでください。レシピ(Stripe、Google Maps、フォント、インラインスタイルの許可)については、references/browser-policy-csp.md を参照してください。

機密性の高いメソッド向けのDDPRateLimiter

import { DDPRateLimiter } from "meteor/ddp-rate-limiter";

DDPRateLimiter.addRule(
  {
    type: "method",
    name: "login",
    clientAddress: () => true,
  },
  5,
  60000,                  // 5 attempts per 60s, per IP
);

レート制限のバケットキーに使われるのは、マッチャーのフィールドだけです。clientAddress、connectionId、userIdがない場合、一致するすべての呼び出し元が1つのグローバルバケットを共有します。Meteor 3.5以降では、データベースに基づく判定に非同期マッチャー関数を使用できます。接続はその完了を待つため、クエリは高速に保ってください。Meteor 3.0から3.4では、マッチャーは同期処理でなければなりません。固定ルール、事前計算した同期状態を使うか、Mongoの処理を待機せずに済むようアップグレードしてください。

accounts-baseには、デフォルトルール(ログイン/サインアップ/パスワードリセットについて、マッチしたメソッドごとにDDP接続あたり10秒間に5回)が含まれています。Meteor 3.6-beta.1の[email protected]では、requestLoginTokenForUserもマッチ対象になります。[email protected]は、検索/作成の前に完全なペイロードを検証します。RCの組み合わせは[email protected]と[email protected]です。コールバックでレート制限エラーが発生した場合は、直ちに再試行を繰り返さないようにしてください。古いアプリでは、両方のパッケージのバージョンを確認してください。デフォルトルールを置き換える場合に限り、Accounts.removeDefaultRateLimit()で削除してください。

[email protected]のCookieを強化するには、meteor-accountsを使用してください。信頼されたオリジン、有効なトークン、キャッシュ禁止レスポンス、SameSite=Strictには、それぞれ固有の移行チェックがあります。HTTPエンドポイントの30回/10秒という制限はクライアントアドレスごとに適用され、DDPとは別です。HttpOnlyストレージを使用しても、同一オリジンで実行されるアクティブなXSSが、DDP認証に使われる再開トークンを取得することは防げません。

OAuthシークレットの暗号化

oauth-encryptionを追加し、16バイトのbase64キー(32バイトではありません)をAccounts.configに渡してください。Meteor.startup内ではなく、モジュールのトップレベルに記述します。

meteor node -e "console.log(require('crypto').randomBytes(16).toString('base64'))"
import { Accounts } from "meteor/accounts-base";

Accounts.config({
  oauthSecretKey: Meteor.settings.oauthSecretKey,
});

起動時に、accounts-oauthはServiceConfiguration.configurations.secretにある未暗号化のプロバイダーアプリケーションシークレットを暗号化します。プロバイダーパッケージは、services.github.accessTokenやTwitterのaccessTokenSecretなど、サポート対象のユーザーごとのトークンフィールドも暗号化します。汎用的なMeteor.users.services.<provider>.secretフィールドはありません。どのユーザー認証情報が暗号化されるかを明示する前に、プロバイダーのスキーマを確認してください。

audit-argument-checks

meteor add audit-argument-checks

すべての引数を対象とするcheck()なしでメソッドまたはパブリケーションが実行されると、例外がスローされます。任意の入力を正当に受け付けるメソッドでは、その旨を明示します。

Meteor.methods({
  rawLog(...args) {
    check(args, [Match.Any]);
    // ...
  },
});

アンチパターン

  • 機密データに対する、制限が緩すぎるクライアント書き込みルール。ガード付きメソッドに置き換えてください。同等のポリシーを確認する前に、保護のための拒否ルールを削除しないでください。
  • Meteor.settings.public.<secret>。クライアントからpublicの内容を参照できます。シークレットはsettings.jsonのトップレベルに移してください。
  • Meteor.usersコレクション全体のパブリッシュ。常に(例:fields: { username: 1, profile: 1 }のように)フィールドを指定し、対象を絞り込んでください。メールアドレスは、所有者または明示的に許可された別の対象にのみパブリッシュしてください。
  • サードパーティースクリプトにBrowserPolicy.content.allowOriginForAllを使用すること。この設定では、すべての現在のコンテンツディレクティブにオリジンが許可されます。連携に必要なスクリプト、フレーム、接続、画像、スタイル、フォントのディレクティブだけを許可してください。
  • コールバック形式の引数を受け付けるメソッド。関数はDDP経由で送信できません。
  • Meteor.startup内でAccounts.config({ oauthSecretKey })を呼び出すこと。OAuthパッケージが読み込む前に設定が読み込まれるよう、モジュールのトップレベルに記述する必要があります。

関連項目

  • references/method-and-publish-guards.md
  • references/browser-policy-csp.md
  • references/eval-cases.md
  • 関連スキル:meteor-methods、meteor-pubsub、meteor-accounts。

コメント