MeshLaw セキュリティ白書
2026-05-21 v0.1 · 法務・IT チーム検討用
本書は MeshLaw のデータ処理・分離・暗号化・アクセス制御ポリシーをまとめたものです。実装の事実(コード・マイグレーション・運用設定)に基づいており、検証やデューデリジェンスの際には該当する行を併せて提示します。
1. システム構成
| コンポーネント | 技術 | 備考 |
|---|---|---|
| ゲートウェイ | Moleculer (Node/Bun) :4098 | HTTP の入口。JWT 検証 + RLS コンテキスト注入 |
| DB | PostgreSQL 16 + pgvector | 単一インスタンス。RLS team_id 分離 |
| AI バックエンド | vLLM(自社ホスティング) | 外部 API への送信なし — マターデータが外部 LLM 事業者へ出ない |
| メール | Resend(ドメイン検証済み) | 登録・パスワードのみ、マター内容の送信なし |
| モバイルプッシュ | APNs + FCM | title/body + data のみ — マター本文なし |
ホスティング: Vultr ソウルリージョン — データは韓国に所在。運用 SSH: 鍵認証のみ(パスワード無効)。
2. テナント分離
2.1 PostgreSQL Row-Level Security
すべてのドメインテーブルで FORCE ROW LEVEL SECURITY を有効化:
- 直接分離(team_id カラム): matters, clients, advisories, audit_log, notifications, llm_usage, team_token_quota, messages, device_tokens, stripe_webhook_events, invoice_receipts
- JOIN 分離(matter_id → matters.team_id): matter_events, invoices, timesheet_entries, writs, approvals, matter_refs, vault_files, matter_acl, deadlines
ポリシー: team_id = app_current_team_id()(USING + WITH CHECK)。app_current_team_id() はトランザクション GUC app.team_id を読み取ります。
2.2 NOSUPERUSER ROLE 分離
運用ゲートウェイは meshlaw_app(NOSUPERUSER · NOBYPASSRLS)ROLE で DB に接続。dev / マイグレーションツールは別の superuser に分離 — 日常の運用トラフィックに BYPASSRLS ユーザが混ざりません。2026-05-05 適用。
2.3 トランザクション GUC 注入
sql.begin(async (tx) =>
await tx`select set_config('app.team_id', ${teamId}, true)`
await tx`select set_config('app.user_id', ${userId}, true)`
return fn(tx)
SET LOCAL なのでトランザクション終了時に自動的に解除されます。50/50 のドメインアクションが wrap を適用。残り 7 件は auth.signup/login の password_hash ルックアップなど意図的な raw — データ漏えい経路はありません。
2.4 JWT → ctx.meta.user マッピング
ゲートウェイの onBeforeCall が JWT を検証 → ctx.meta.user = { id, team, role } を注入。すべてのドメインルートが AUTH_REQUIRED_PREFIXES に含まれ、トークンがなければ 401。
2.5 リグレッション保護
テナント分離は、毎回のデプロイ前に e2e §7(RLS)でリグレッションテストします:
- 未認証の呼び出し → 401
- 不正な JWT → 401
- 正常な JWT は自分の team のデータのみ到達 → 200
3. 個人情報保護(PII)
3.1 住民登録番号
保存: pgp_sym_encrypt 暗号化(BYTEA rrn_encrypted)+ 末尾 4 桁(rrn_last4)。表示: クライアント UI は maskRRN() で強制マスキング → XXXXXX-XXX{last4}。形式が合わない場合は空文字列(raw 表示を遮断)。8 件のユニットテストでリグレッション。
3.2 パスワード
bcrypt ハッシュで保存。クライアントは入力時に 4 ルールをリアルタイムに可視化(8 文字 / 英字 / 数字 / 特殊文字)。HTTPS only — iOS Release ビルドは NSAllowsArbitraryLoads を未設定。
3.3 トークン管理
- JWT: 短い TTL(既定 30 分)、HS256
- Refresh: rotation + reuse detection。平文はユーザに 1 回だけ渡し、DB には bcrypt ハッシュのみ。再使用を検知すると chain 全体を revoke
3.4 マター単位 ACL
RLS の team スコープの上に、マター単位の追加分離(matter_acl)。4 ロール(owner ⊃ editor ⊃ viewer)。メッセンジャー v0.1.6 が採用 — マターのチャネル一覧は viewer 以上、書き込みは editor 以上。
4. 監査ログ
audit_log テーブルに自動記録されるアクション:
- マター CRUD、ACL grant/revoke
- 承認の承認/却下/修正依頼(status_before/after, comment)
- 請求書の発行、入金 receipt(delta_won, total)
- 使用量 → invoice/timesheet rollup
- 参考文書 CRUD
各 row: actor_name, target_kind, target_id, http_status, matter_id, meta(JSONB), created_at。RLS 適用 — 他テナントの audit は照会不可。
5. 権限制御
5.1 承認(matter approvals)
サーバ側 actor ガード — computeApprovalChainAdvance(steps, status, currentUserId)。アクティブな段階の approver_id と一致するユーザのみがアクション可能。不一致なら 403 NOT_APPROVER。デスクトップ・モバイルで同一ガード。7 件のユニットテスト。
5.2 RBAC(システムロール)
users.role_id → roles テーブル(admin/partner/associate/staff)。auth.invite がロールを付与(admin のみ発行可能)。
6. データ処理
6.1 AI モデル呼び出し
自社 vLLM(Tailscale 内部網)— 外部 API への送信なし。LLM リクエスト本文(マターコンテキスト・文書)は社外へ出ません。llm_usage テーブルに呼び出しトークン・コストを記録(RLS team スコープ)。
6.2 ファイル(Vault)
- 保存: サーバディスク(
storage_directoryをマターごとに分離) - メタデータ:
vault_filesテーブル(file_name, mime, size_bytes, text_content) - インデックス: テキスト抽出後に
text_contentへ保存 → ⌘K 統合検索(RLS 適用) - PDF マルチモーダル: mupdf でページを JPEG 変換 → vLLM のビジョンエンコーダ(外部へ出ない)
6.3 メール
Resend ドメイン meshlaw.ai(DKIM/SPF/DMARC 検証済み)。コンテンツ: 登録・invite・パスワード再設定のみ — マター内容なし。
7. インフラセキュリティ
7.1 伝送
ゲートウェイ: HTTPS only(Caddy)。iOS Release / Android Release はいずれも prod URL のみ(Debug のみ localhost)。
7.2 モバイルプッシュ
- APNs JWT (.p8) — Apple Developer Team ID + Key ID
- FCM HTTP v1 — Firebase service account JSON
- プッシュ本文はメタデータのみ(title/body + data.type ルーティング hint)— マター本文なし
- デバイストークン:
device_tokensテーブル(RLS team スコープ)
7.3 運用アクセス
- SSH 接続: 鍵ベース認証(運用推奨)
- DB: docker-compose が
127.0.0.1:54322に localhost bind only — 外部インターネットへの露出なし。ホスト内のゲートウェイコンテナのみアクセス可能(network_mode: host) - バックアップ:
/var/backups/meshlaw-db-*.sql.gz(現在は手動、自動化予定) - マイグ適用時は事前バックアップ必須(運用規律)
7.4 Stripe 決済
Webhook signature 検証 + 冪等性ガード(stripe_webhook_events)。カード情報は Stripe Vault — 自社保存なし(PCI 範囲の最小化)。
8. コンプライアンス姿勢
| 項目 | 状態 |
|---|---|
| 個人情報保護法(PIPA) | 通常処理 · DPA を別途提供 |
| ISMS-P | 検討中(認証申請時点で別途告知) |
| KISA マーク | 検討中 |
| GDPR | 適用外(国内限定) |
| ZDR (Zero Data Retention) | ポリシーオプション — Pro+ プラン契約時の約定附属。現在は自社 vLLM のみ使用のため、外部学習への露出自体がない |
⚠️ ISMS-P / KISA マークは検討段階です。認証マークの使用は取得後にのみ可能です。
9. インシデント対応
9.1 トークン漏えい
Refresh の再使用を検知するとユーザの chain 全体を自動 revoke。/auth/logout またはパスワード変更 → すべての refresh を revoke。
9.2 データ露出
発見後ただちに docker-compose ロールバック + DB バックアップ復元。
9.3 ユーザ通知
ポリシー目標: 72 時間以内に影響範囲・復旧手順・ユーザのアクションを案内(個人情報保護法 §34 勧告レベル)。現在は自動化なし — 発生時は運用者が手動で影響範囲を算出し、一括メールを送信。
10. データ移転・削除
- Export: ユーザが自分の team データを JSON で export(v0.2 予定)
- 削除: UI からの直接削除 + アカウント削除はメール依頼 → 30 日 grace → cascade
- 保管: 既定で無期限。法定の義務保管(所得税法 5 年など)はユーザの責任
11. 検証リクエスト
本白書の事実検証・デューデリジェンス協力をご希望の場合は、contact ページまたは営業担当のメールへリクエストください — コード経路(行番号)· マイグ SQL の写し · 侵入テスト結果(実施後)を提供します。
専用のセキュリティ用メールボックス(compliance@meshlaw.ai など)は、ドメイン検証および運用準備の完了後に別途告知します。
⌘P (Mac) / Ctrl+P (Win) で「PDF として保存」。または Markdown 原本をダウンロード。