セキュリティ証跡
概要
本文書は Ritsubi E-Commerce のセキュリティ対策状況を記録する。継続的に更新し、脆弱性管理の証跡とする。
脆弱性スキャン結果
Trivy スキャン(2026-05-29 実施)
Scanner: Trivy vX.X (vulnerability scanner)
対象: リポジトリルート(除外: apps/wordpress-cms/vendor, node_modules 直下)
| 重篤度 |
件数 |
プロダクション影響 |
| CRITICAL |
0 |
なし |
| HIGH |
14 |
なし(後述) |
| MEDIUM |
0 |
なし |
| LOW |
0 |
なし |
HIGH 脆弱性の内訳
| CVE |
パッケージ |
検出箇所 |
プロダクション影響 |
対応方針 |
| CVE-2026-35209 |
defu 6.1.4 |
apps/storefront/.npm-cache/_npx/.../package-lock.json |
なし — ローカルキャッシュのみ |
キャッシュクリアで除去 |
| CVE-2026-26996 / CVE-2026-27903 / CVE-2026-27904 |
minimatch 3.1.2 |
apps/storefront/.npm-cache/_npx/.../package-lock.json |
なし — ローカルキャッシュのみ |
キャッシュクリアで除去 |
| CVE-2026-33671 |
picomatch 2.3.1 / 4.0.3 |
apps/storefront/.npm-cache/_npx/.../package-lock.json |
なし — ローカルキャッシュのみ |
キャッシュクリアで除去 |
| CVE-2025-68429 / CVE-2026-27148 |
storybook 10.0.0 |
apps/storefront/.npm-cache/_npx/.../package-lock.json |
なし — ローカルキャッシュのみ |
キャッシュクリアで除去 |
| CVE-2025-64756 |
glob 10.4.5 |
@zenuml/core/bun.lock(ドキュメントツール) |
なし — ドキュメント生成ツールのみ |
次回 @zenuml/core アップデート時に追従 |
| CVE-2026-4800 |
lodash 4.17.21 |
@zenuml/core/bun.lock(ドキュメントツール) |
なし — ドキュメント生成ツールのみ |
次回 @zenuml/core アップデート時に追従 |
結論: 現時点でプロダクション影響のある脆弱性は 0 件。
次回スキャン
定期スキャンは pnpm audit を CI に組み込み、CRITICAL/HIGH の新規検出時はアラートを出すことを推奨する(REQ-032 として追跡)。
暗号化状態
通信暗号化
| 通信経路 |
プロトコル |
証明書管理 |
状態 |
| 顧客 ↔ Storefront |
HTTPS / TLS 1.3 |
Cloudflare 自動管理 |
✅ 有効 |
| 顧客 ↔ Vendure API |
HTTPS / TLS 1.3 |
Fly.io 自動管理 |
✅ 有効 |
| 顧客 ↔ WordPress |
HTTPS / TLS 1.3 |
Let's Encrypt(VPS) |
✅ 有効 |
| Storefront ↔ Vendure API |
HTTPS |
Fly.io 自動管理 |
✅ 有効 |
| Vendure ↔ PostgreSQL |
TLS(Fly 内ネットワーク) |
Fly.io 自動管理 |
✅ 有効 |
| Vendure ↔ Redis |
TLS(Fly 内ネットワーク) |
Fly.io 自動管理 |
✅ 有効 |
保存データの暗号化
| データ |
暗号化方式 |
管理場所 |
状態 |
| PostgreSQL ストレージ |
Fly.io Volume(OS レベル暗号化) |
Fly.io |
✅ 有効 |
| R2 バケット(メディア) |
Cloudflare R2 自動暗号化 |
Cloudflare |
✅ 有効 |
| Secrets / API キー |
AWS Secrets Manager |
AWS |
✅ 有効 |
| 顧客パスワード |
bcrypt ハッシュ(Vendure 標準) |
PostgreSQL |
✅ 有効 |
決済関連の暗号化
SB Payment Service は TLS 1.2 以上を要求する。
継続追跡事項(SHA-1 リスク): SB Payment の一部サーバー証明書に SHA-1 が含まれる可能性がある。
- リスク: SHA-1 署名の証明書は段階的に廃止中(ブラウザ互換性問題の可能性)
- 現状: SB Payment 側の問題であり、当社からの直接制御は困難
- 対応: SB Payment への定期的な証明書更新確認、ブラウザコンソールエラーの Sentry 監視で検知
アクセス制御
管理画面
| 対象 |
認証方式 |
アクセス制御 |
状態 |
| Vendure Dashboard(React) |
Vendure ネイティブ認証(JWT) |
ロールベース(Administrator / Operator) |
✅ 有効 |
| WordPress 管理画面 |
WordPress 認証 |
IP 制限 + 強パスワードポリシー |
✅ 有効 |
| Fly.io Dashboard |
Fly.io 認証(SSO) |
GitHub Org メンバーのみ |
✅ 有効 |
| Cloudflare Dashboard |
Cloudflare 認証(SSO) |
GitHub Org メンバーのみ |
✅ 有効 |
API エンドポイント
| エンドポイント |
認証 |
レート制限 |
入力検証 |
状態 |
Storefront /api/auth-login |
不要 (login mutation を内部 proxy) |
Cloudflare Workers Rate Limit binding (AUTH_LOGIN_RATE_LIMIT, IP/60s/10req) |
same-origin 強制 + 仮 password 12 文字 |
✅ 有効 |
| Storefront API(公開・その他) |
不要(公開データ) |
Cloudflare WAF |
same-origin 強制 |
✅ 有効 |
| Vendure Shop API |
セッションまたは JWT |
Cloudflare WAF (shop-api 全体 rate limit は Issue #840 で追加予定) |
Origin validator (fail-closed in prod) + GraphQL depth limit (max 12) |
✅ 有効 |
| Vendure Admin API |
JWT(管理者のみ) |
IP + Cloudflare WAF |
Origin validator + HardenPlugin (complexity 2500 strict) |
✅ 有効 |
実施済みセキュリティ対策(2026-05-24 audit-driven 改善)
第三者 audit (security-auditor / quality-engineer / performance-engineer 並列調査) で
検出された High 案件に対する正面対応の記録。本セクションは「なぜそうしたか」を
専門観点で明示し、将来の見直し基準を示す。
1. Vendure session cookie SameSite=lax 統一 + Origin validator middleware
- 対応ファイル:
apps/vendure-server/src/config/auth-options.ts
apps/vendure-server/src/middleware/origin-validator.middleware.ts (新規)
apps/vendure-server/src/middleware/origin-validator.middleware.spec.ts (新規, 7 ケース)
apps/vendure-server/src/config/api-options.ts
- 変更内容:
- 旧 production
sameSite: "strict" → 全環境 "lax" に統一
Origin → Referer 順で CORS allowlist と照合する middleware を apiOptions.middleware の先頭に配線
- SAFE method (GET/HEAD/OPTIONS) は素通し、
bypassRoutes: ["/payments/sbps", "/webhooks"] で server-to-server callback を除外
- allowlist 空時は fail-safe で warn + passthrough(env 設定漏れで production 全停止を回避)
- 専門観点での判断根拠:
- SameSite=strict が止めるのは「攻撃者サイトに誘導された被害者ブラウザの cross-site state-changing リクエストへの cookie 同梱」だが、Vendure の state-changing は (a) GraphQL POST、(b)
Content-Type: application/json (CORS preflight 強制)、(c) @Allow permission check で三重防御済み
- simple POST 経路 (
<form> enctype:application/x-www-form-urlencoded) は admin/shop API に存在しない
- 一方 SBPS cross-site redirect 後の session 喪失リスクは桁違いに高い → trade-off で
lax が合理的
- 補完として Origin validator を同時投入し、
lax の attack surface を strict 相当に縮約
- Rollout:
- cookie の
name / domain / path 変更なしのため既存 session 即時失効は発生しない見込み
- rollback は
auth-options.ts の sameSite 戻し再 deploy のみ(migration 不要)
- staging 一巡 (SBPS 通常 + callback タイムアウト + 再決済) 確認後に production 適用
- 詳細は
docs/03-implementation/payments/sb-payment-link.md の deploy ガード節
1-b. Session 保持期間(sessionDuration)
- 対応ファイル:
apps/vendure-server/src/config/auth-options.ts
- 設定値:
- staging / production:
7d
- local dev:
30d
- Redis session cache の
ttl も同じ値(dev 30 日 / prod 7 日)で揃える
- 適用範囲: Vendure Shop API / Admin API いずれも同一。Storefront (Vite + TanStack Router on Cloudflare Workers) は独自の cookie
maxAge を設定せず、Vendure 発行 session cookie の expiry に追従する。
- 判断根拠:
- 7 日は B2B ECで「平日ログインしたまま週末を跨いで業務再開」を許容しつつ、PC 共用や端末紛失時の暴露窓を 1 週間以内に抑える妥協点
- dev で 30 日にしているのは開発者の再ログイン頻度を下げるためで、
IS_DEV ガードで本番に漏れない
- 変更時の手順: staging で一巡確認 → production 反映。cookie 名・domain・path は変えないため既存 session の即時失効は発生しない。
2. 仮 password 強度向上 (8 → 12 文字)
- 対応ファイル:
packages/domain/src/rules/customer.ts:49 TEMPORARY_LOGIN_PASSWORD_LENGTH = 12
packages/domain/src/rules/customer.spec.ts 範囲 assertion (>=12) へ
- 変更前: 8 文字 × alphabet 47 → エントロピー ~44.6 bits
- 変更後: 12 文字 × alphabet 47 → エントロピー ~66.7 bits(目標 64 bits 超え)
- 背景: SMILE インポート (
packages/plugins/src/system-integration/smile/services/csv-import-customer.processor.ts) で複数顧客に並列発行され、メール配布までの遅延を考慮するとオフライン brute-force 余地を縮める必要
- alphabet 方針: 既存どおり記号と紛らわしい文字を除外(メール・口頭で共有可能性を維持)
3. GraphQL depth limit (max 12) を Shop API に導入
- 対応ファイル:
apps/vendure-server/src/config/graphql-depth-limit.ts (新規)
apps/vendure-server/src/config/api-options.ts
- 変更内容: 標準
graphql の validation rule のみで実装した always-on maxDepth = 12 を shopApiValidationRules に注入。introspection (__schema 等) は除外して tooling 互換を維持
- 判断根拠:
- 新規 npm 依存(
graphql-armor / graphql-depth-limit)追加は production リスクを増やすため避け、標準 API のみで完結
- 既存
HardenPlugin (apps/vendure-server/src/config/plugins.ts:127) は env flag VENDURE_HARDEN_PLUGIN_ENABLED でゲート。本 PR では env を変えず、depth limit 単独の防御を always-on で提供
4. AGENTS ガードレール追記
apps/vendure-server/AGENTS.md に 1 行:
- 「session cookie は全環境
lax を維持、CSRF 防御は origin-validator.middleware.ts で補完、apiOptions.middleware 先頭への配線必須、server-to-server callback は bypassRoutes で除外」
- Storefront Worker → Vendure 呼び出しの upstream origin 規約も同 AGENTS に追記(Worker 入口でブラウザ起点 request の same-origin を検証し、Vendure へは
VITE_PUBLIC_SITE_URL / SITE_URL の canonical origin を渡す)。
6. Production hardening(2026-05-27)
production 開始前 audit で検出された High / Medium 案件への正面対応。詳細は各 PR 参照。
6-a. Swagger /api-docs を production で既定無効化
- 対応ファイル:
apps/vendure-server/src/index.ts, packages/contract/src/validation/apps.ts
- 変更内容:
apiDocsEnabled を env.VENDURE_API_DOCS_ENABLED ?? env.NODE_ENV !== "production" に変更。production では Swagger UI / OpenAPI JSON を serve しない。
- 判断根拠: System Integration の webhook spec を外部に露出させないため。production で一時的に有効化したい場合は env で明示 opt-in。
6-b. originValidator を production で fail-closed 化
- 対応ファイル:
apps/vendure-server/src/middleware/origin-validator.middleware.ts, apps/vendure-server/src/config/api-options.ts
- 変更内容:
emptyAllowlistMode: "warn-and-pass" | "reject" option を追加し、production では "reject" を渡す。
- production 起動時に allowlist が空なら process abort (CORS_ORIGIN / STOREFRONT_URL / ADMIN_URL のいずれかが必須)。
- 判断根拠: AGENTS.md「黙った fail-open を避ける」原則。env 設定漏れによる CSRF 防御の silent disable を防ぐ。
6-c. HardenPlugin の production 必須化(SEC-005 解消)
- 対応ファイル:
apps/vendure-server/src/config/plugins.ts
- 変更内容: production で
VENDURE_HARDEN_PLUGIN_ENABLED が true でなければ起動時に throw。
- 運用: Fly secret に
VENDURE_HARDEN_PLUGIN_ENABLED=true を設定して deploy する。
- 対応ファイル:
apps/vendure-server/src/middleware/security-headers.middleware.ts (新規), apps/vendure-server/src/config/api-options.ts
- 変更内容: 全レスポンスに
X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy を付与。production / staging では HSTS を強制。
- 判断根拠: Storefront 側は既に
applyStorefrontResponseSecurityHeaders で実装済みだが、Vendure 側 (admin-api / shop-api / system-integration) は無防備だった。
6-e. /api/auth-login の Cloudflare Rate Limit binding(SEC-004 解消)
- 対応ファイル:
apps/storefront/src/worker-api/rate-limit.ts (新規)
apps/storefront/src/worker-api/handlers/auth.ts
apps/storefront/wrangler.toml (全 env に [[unsafe.bindings]] type = "ratelimit" を追加)
- 変更内容: Cloudflare Workers Rate Limiting binding を使い、IP / 60s window / 10 req を上限に。binding 未設定の dev / ローカルでは素通り (fail-open)。
- 判断根拠: KV ベース実装より低レイテンシ・low ops。Cloudflare 内蔵 sliding window counter で、同一アカウント内で
namespace_id 別 (production=1101, preview=1102, staging=1103, mock=1104) によりカウンタ分離。
6-f. storefront logger の LOG_LEVEL filter
- 対応ファイル:
apps/storefront/src/lib/logger.ts, apps/storefront/src/env.schema.ts
- 変更内容:
STOREFRONT_LOG_LEVEL / LOG_LEVEL env で最小出力 level を制御。未設定時は production / staging で info 以上に絞り、Cloudflare Workers logs の signal/noise を改善。
5. Storefront Worker → Vendure の upstream origin 正規化(2026-05-25 更新)
- 対応ファイル:
apps/storefront/src/worker-api/vendure-client.ts (buildVendureHeaders)
apps/storefront/src/worker-api/handlers/commerce.ts (proxyCommerceRequest)
- 背景:
- 上記 1. の origin-validator middleware 導入時、Storefront Worker → Vendure shop-api 経路の Origin 転送が抜けており、login mutation / カート操作など全 state-changing GraphQL が 403
Forbidden: missing Origin/Referer for state-changing request で落ちた(手動検証で発覚: test1@ritsubi-platform.com / 開発 password でログイン不可)。
- 2026-05-25 に
medical.ritsubi.co.jp alias からの production login と /commerce/shop-api が失敗した。原因は Worker が alias domain の Origin を Vendure へ渡し、Vendure allowlist と公開 alias 運用が drift したこと。
- 修正方針 (採用): Worker 入口で browser の same-origin を検証し、Vendure へは canonical Storefront origin を渡す。
- ブラウザ起点 → Worker で
Origin / Referer が request URL と同一 origin であることを検証する。
- Worker → Vendure →
VITE_PUBLIC_SITE_URL / SITE_URL の canonical origin(production は https://order.ritsubi-platform.com)を Origin として送る。/commerce proxy では Referer も canonical に正規化する。
- 二段防御: Worker 入口で alias を含む同一 origin を強制 → Vendure 側では Storefront canonical origin のみを server-to-server caller として検証する。
- 却下した代替案:
- 「公開 alias をすべて Vendure allowlist に追加する」: alias 追加・削除と Vendure deploy がずれるたびに再発する。
- 「Vendure 側で内部 caller 専用 bypass header (shared secret)」: secret 管理コストが増え、SBPS bypassRoutes と二系統になる。canonical origin 正規化なら既存の allowlist 設計だけで一貫する。
- 専門観点での判断根拠:
- origin-validator は元々「ブラウザ起点 CSRF」を仮定するが、Cloudflare Worker が Storefront の同一 origin boundary になっているため、browser origin 検証は Worker 入口で完了させるのが責務境界として正しい。
- alias domain を Vendure へ流さないことで、Storefront の公開入口追加と Vendure の CORS / origin allowlist が密結合しない。
- SBPS 等の本物の server-to-server callback は
bypassRoutes で従来通り除外されるため影響なし。
既知のセキュリティリスクと追跡
| ID |
リスク |
重篤度 |
現状 |
対応計画 |
| SEC-001 |
SB Payment SHA-1 証明書の可能性 |
MEDIUM |
監視中 |
SB Payment への確認・Sentry アラート設定 |
| SEC-002 |
旧システムからの移行ユーザーパスワードの再設定 |
HIGH |
Issue #780 で追跡 |
パスワード再設定メール送信フロー実装(REQ-031 待ち) |
| SEC-003 |
管理者アカウントの定期的なパスワード更新ポリシー |
LOW |
未実装 |
ポリシー文書化・Vendure Dashboard での通知 |
| SEC-004 |
/api/auth-login の brute-force rate limit |
HIGH |
✅ 実装済み (2026-05-27) |
Cloudflare Workers Rate Limiting binding AUTH_LOGIN_RATE_LIMIT (IP / 60s / 10 req) を apps/storefront/src/worker-api/handlers/auth.ts で適用。namespace_id は env 別 |
| SEC-005 |
HardenPlugin (GraphQL complexity 2500 strict 運用) を production env で有効化 |
MEDIUM |
✅ 実装済み |
apps/vendure-server/src/config/plugins.ts で production 起動時に VENDURE_HARDEN_PLUGIN_ENABLED=true を必須化し、maxQueryComplexity=2500 で過大 query を fail-closed する |
| SEC-006 |
Double-submit CSRF token (Dashboard ↔ Admin API) |
MEDIUM |
未実装 |
Origin validator で代替防御中。本格対応は Dashboard 側 UI 改修 + worker header 付与が必要 → 別 PR |
| SEC-007 |
SBPS service log で response payload に PII (sps_cust_no 等) を含む JSON.stringify |
MEDIUM |
既存実装 |
packages/plugins/src/payment-integration/sb-payment-link/sb-payment-link.service.ts:306,437,488,581 に専用 sanitizer を導入 |
| SEC-008 |
ctx.activeUserId ?? "" の silent fail-open (points.shop.resolver.ts:22,34,43) |
MEDIUM |
既存実装 |
ForbiddenError で fail-closed 化 |
| SEC-009 |
SBPS callback の simulatorMode === true で amount 検証 skip |
MEDIUM |
既存実装 |
production NODE_ENV で simulatorMode を起動時 reject |
| SEC-010 |
SMILE CSV import の upload size 制限不在 |
MEDIUM |
既存実装 |
apiOptions.uploadMaxFileSize 明示 + processor 入口で行数 cap |
変更履歴
| 日付 |
変更内容 |
担当 |
| 2026-05-29 |
初版作成(Trivy スキャン結果・暗号化状態・アクセス制御を記録) |
AI Agent |
| 2026-05-24 |
audit-driven 改善: SameSite=lax 統一 + Origin validator middleware / 仮 password 強度 12 文字 / GraphQL depth limit / 追跡項目 SEC-004〜010 追加 |
AI Agent |
| 2026-05-27 |
Production hardening: Swagger 既定無効化 / originValidator fail-closed / HardenPlugin fail-fast (SEC-005 解消) / Vendure security header middleware / /api/auth-login Rate Limit binding (SEC-004 解消) / storefront logger LOG_LEVEL filter |
AI Agent |