بنقرة واحدة
spec-security
セキュリティ・脆弱性対策の開発・テストを行う際に使用。OAuth/OIDC攻撃対策、認証識別子切り替え攻撃、Session Fixation、マルチテナント分離、セキュリティテスト実装時に役立つ。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
セキュリティ・脆弱性対策の開発・テストを行う際に使用。OAuth/OIDC攻撃対策、認証識別子切り替え攻撃、Session Fixation、マルチテナント分離、セキュリティテスト実装時に役立つ。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
UserInfoエンドポイント(UserInfo Endpoint)機能の開発・修正を行う際に使用。UserInfo claims、scopeフィルタリング、verified_claims実装時に役立つ。
外部API認証ユースケースの設定ガイド。外部API連携(認証委譲、リスク判定、OTP等)の interaction 設計、identity_match_field、MFA 2段階目、previous_interaction のヒアリングと設定JSONを提供。
ユースケース別セットアップのエントリポイント。ユーザーにユースケースを選択してもらい、対応するスキル(use-case-login, use-case-mfa等)にルーティングする。共通ワークフロー、前提条件、組み合わせパターンの概要を提供。
認証機能(Authentication Policy, MFA)の開発・修正を行う際に使用。認証ポリシー、パスワード、OTP、FIDO2、条件付き認証実装時に役立つ。
外部サービス連携(External Service Integration)機能の開発・修正を行う際に使用。HTTP Request Executor, MappingRule, OAuth/HMAC認証実装時に役立つ。
FIDO2/WebAuthn/パスキー関連の実装・設定・ドキュメント・テストを扱う時に使用。パスキー登録、認証、管理、アテステーション検証に関する作業で自動的に呼び出される。
| name | spec-security |
| description | セキュリティ・脆弱性対策の開発・テストを行う際に使用。OAuth/OIDC攻撃対策、認証識別子切り替え攻撃、Session Fixation、マルチテナント分離、セキュリティテスト実装時に役立つ。 |
e2e/src/tests/security/README.md - セキュリティテスト詳細documentation/docs/content_11_learning/06-security/ - セキュリティ学習リソース| 脆弱性 | CWE | 重大度 | 対策 |
|---|---|---|---|
| 認証識別子切り替え攻撃 | CWE-287 | Critical | 1st factor: DB検索優先化 / 2nd factor: 認証済みユーザーへバインド |
| Redirect URI切り替え攻撃 | CWE-601 | Critical | 完全一致検証 |
| Session Fixation | CWE-384 | High | 認証後Session再生成 |
| 認可コード再利用 | CWE-294 | High | 使用後即時削除 |
| マルチテナント分離違反 | CWE-284 | Critical | Tenant第一引数パターン |
| SSRF | CWE-918 | High | プライベートIP/メタデータブロック |
| パスワードブルートフォース | CWE-307 | High | Redisカウンター(INCR+TTL) |
| Null Byte Injection | CWE-626 | High | MaliciousRequestRejectFilter(Servlet Filter) |
| Oversized Request Body | CWE-400 | Medium | MaliciousRequestRejectFilter(10MB制限)+ nginx + AWS API Gateway |
1. 被害者のメールアドレスAで認証開始
2. チャレンジ送信後、攻撃者メールアドレスBに変更
3. Bの検証コードで認証
4. 【脆弱】: メールアドレスAとしてログイン ❌
5. 【正常】: メールアドレスBとしてログイン ✅
EmailAuthenticationInteractor.java:257-306:
private User resolveUser(
Tenant tenant,
AuthenticationTransaction transaction,
String email,
String providerId,
UserQueryRepository userQueryRepository) {
// === 1st factor user identification ===
// 1. Database search FIRST (Issue #800 fix)
User existingUser = userQueryRepository.findByEmail(tenant, email, providerId);
if (existingUser.exists()) {
log.debug("User found in database. email={}, sub={}", email, existingUser.sub());
return existingUser;
}
// 2. Reuse transaction user if same identity (Challenge resend scenario)
if (transaction.hasUser()) {
User transactionUser = transaction.user();
if (email.equals(transactionUser.email())) {
return transactionUser; // Same identity -> reuse
}
// Different identity -> create new user (identifier switching)
}
// 3. New user creation...
}
e2e/src/tests/security/identifier_switching_attack.test.js
1st factor の DB検索優先化に加え、password を 2nd factor(requires_user: true)に使う場合は、検証対象を入力 username ではなくセッションの認証済みユーザーに固定する。これがないと、1段目を被害者として通過後、2段目に別アカウントの正しい credential を提示して被害者としてログインできてしまう(バインド欠落 = identifier switching の別経路)。
PasswordAuthenticationInteractor(2nd factor):
requires_user && hasUser: execution request の username / provider_id を transaction.user() の値に上書きしてから executor を呼ぶ → パスワードは本人の hash に対して照合されるrequires_user && !hasUser: executor 実行前に拒否(user_not_found)EmailAuthenticationChallengeInteractor#resolveEmail(2nd factor で request 入力を無視)と同じ作法。
セキュリティテスト:
e2e/src/tests/usecase/mfa/mfa-22-password-second-factor-user-binding.test.js
| 攻撃パターン | 説明 | 対策 |
|---|---|---|
| Token Endpoint不一致 | 認可時と異なるredirect_uriでトークン取得 | 完全一致検証 |
| 未登録URI | 登録されていないredirect_uriを使用 | 登録URI必須 |
| 部分一致攻撃 | example.com/callback.evil.com | 厳密一致(substring禁止) |
| URIエンコーディング | %2e%2e/ でパストラバーサル | 正規化後検証 |
// redirect_uri検証(RFC 6749 Section 4.1.3)
// "values MUST be identical"
// NG: 部分一致
if (registeredUri.startsWith(requestUri)) // ❌
// OK: 完全一致
if (registeredUri.equals(requestUri)) // ✅
e2e/src/tests/security/redirect_uri_switching_attack.test.js
テストケース(21件):
1. 攻撃者がSession IDを取得
2. 被害者に固定Session IDでアクセスさせる
3. 被害者が認証完了
4. 【脆弱】: 攻撃者が同じSession IDで被害者としてアクセス ❌
5. 【正常】: 認証後にSession ID再生成 ✅
認証成功後にセッションを再生成し、旧セッションIDを無効化。
e2e/src/tests/security/session_fixation_password_auth.test.js
"The authorization server MUST ensure that authorization codes cannot be used more than once."
AuthorizationCodeGrantService.java:131-134, 202:
// 存在確認
if (!authorizationCodeGrant.exists()) {
throw new TokenBadRequestException("invalid_grant", "not found authorization code.");
}
// ... トークン発行処理 ...
// 使用後は即時削除(再利用防止)
authorizationCodeGrantRepository.delete(tenant, authorizationCodeGrant);
// ✅ 全Repository操作でTenant第一引数
public interface UserRepository {
User find(Tenant tenant, UserId userId);
void register(Tenant tenant, User user);
}
// ❌ Tenant指定なし(テナント間データ漏洩リスク)
public interface UserRepository {
User find(UserId userId); // 危険
}
-- RLSポリシーでテナント分離を強制
CREATE POLICY tenant_isolation ON users
USING (tenant_id = current_setting('app.current_tenant')::uuid);
e2e/src/tests/security/multi_tenant_isolation.test.js
PrivateIpRange.java:
| 種別 | IPレンジ | 説明 |
|---|---|---|
| IPv4 Loopback | 127.0.0.0/8 | ループバック |
| RFC1918 Private | 10.0.0.0/8 | プライベート(Class A) |
| RFC1918 Private | 172.16.0.0/12 | プライベート(Class B) |
| RFC1918 Private | 192.168.0.0/16 | プライベート(Class C) |
| Cloud Metadata | 169.254.169.254/32 | AWS/GCP/Azure メタデータ |
| Link-Local IPv4 | 169.254.0.0/16 | リンクローカル |
| CGNAT | 100.64.0.0/10 | Carrier-Grade NAT (RFC6598) |
| Documentation | 192.0.2.0/24 | TEST-NET-1 |
| Documentation | 198.51.100.0/24 | TEST-NET-2 |
| Documentation | 203.0.113.0/24 | TEST-NET-3 |
| Broadcast | 255.255.255.255/32 | ブロードキャスト |
| Current Network | 0.0.0.0/8 | 現在のネットワーク |
| IPv6 Loopback | ::1/128 | IPv6ループバック |
| IPv6 Link-Local | fe80::/10 | IPv6リンクローカル |
| IPv6 ULA | fc00::/7 | IPv6ユニークローカル |
| IPv4-mapped IPv6 | ::ffff:0:0/96 | IPv4マップドIPv6 |
SsrfProtectionValidator.java:261-274:
private void validateIpAddress(String host, InetAddress address) {
String ipString = address.getHostAddress();
for (PrivateIpRange range : blockedRanges) {
if (range.contains(address)) {
throw new SsrfProtectionException(
String.format(
"Blocked: Host '%s' resolves to private/reserved IP %s (%s)",
host, ipString, range.description()),
host,
ipString,
range);
}
}
}
詳細は /ops-system-config スキル参照。
1. 攻撃者がCIBA/OAuth/管理APIのパラメータにUTF-8 0x00(null文字)を含めて送信
2. 【脆弱】: PostgreSQLが "invalid byte sequence for encoding UTF8: 0x00" で500エラー ❌
3. 【正常】: Servlet Filterで事前検出し400 Bad Requestを返却 ✅
MaliciousRequestRejectFilter.java — Servlet Filterで全APIを一括防御:
getParameterNames() / getParameterValues() でチェック@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 5)
public class MaliciousRequestRejectFilter extends OncePerRequestFilter {
private static final int MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
// query params, form body, JSON body全てをチェック
// Null byte検出時: {"error":"invalid_request","error_description":"Invalid parameter value"}
// サイズ超過時: {"error":"invalid_request","error_description":"Request body too large"}
}
| レイヤー | 制限 | レスポンス形式 |
|---|---|---|
| AWS API Gateway(本番) | 10MB | API Gatewayエラー |
| nginx(ローカル) | client_max_body_size 20m | HTML 413 |
| MaliciousRequestRejectFilter | 10MB(MAX_BODY_SIZE) | JSON 413 |
e2e/src/tests/spec/malicious_request_reject_filter.test.js
テストケース(5件):
e2e/src/tests/security/invalid_user_status_authorization.test.js
cd e2e
npm test -- security/
# 認証識別子切り替え
npm test -- security/identifier_switching_attack.test.js
# Redirect URI攻撃
npm test -- security/redirect_uri_switching_attack.test.js
# Session Fixation
npm test -- security/session_fixation_password_auth.test.js
# マルチテナント分離
npm test -- security/multi_tenant_isolation.test.js
# MaliciousRequestRejectFilter (Null Byte Injection + Payload Size)
npm test -- --testPathPattern="malicious_request_reject_filter"
describe("Security: [攻撃名]", () => {
it("Should prevent [攻撃シナリオ]", async () => {
// 1. 攻撃準備
const victim = createVictimUser();
const attacker = createAttackerUser();
// 2. 攻撃実行
const result = await executeAttack(victim, attacker);
// 3. 脆弱性検証
if (result.authenticatedAs === victim) {
fail("CRITICAL: Attack succeeded - vulnerability exists");
}
// 4. 正常動作確認
expect(result.authenticatedAs).toBe(attacker);
});
});
| OWASP | 対策 |
|---|---|
| A01 Broken Access Control | Tenant分離、認可検証 |
| A02 Cryptographic Failures | JWT署名検証、TLS必須 |
| A03 Injection | パラメータバインディング、Null Byte Rejection |
| A04 Insecure Design | 認証フロー設計レビュー |
| A05 Security Misconfiguration | SSRF保護、デフォルト拒否 |
| A07 Identification Failures | 識別子切り替え対策 |
| スキル | 用途 |
|---|---|
/ops-system-config | SSRF保護、Trusted Proxies |
/spec-security-event | セキュリティイベント通知 |
/spec-session | セッション管理 |
/spec-authentication | 認証実装 |
/test-e2e | テスト実行方法 |