セキュリティ・脆弱性対策の開発・テストを行う際に使用。OAuth/OIDC攻撃対策、認証識別子切り替え攻撃、Session Fixation、マルチテナント分離、セキュリティテスト実装時に役立つ。
Scanned 9/12/2026
Install to Claude Code
npx -y skills add aibot88/sec_skill_store --skill hirokazu-kobayashi-koba-hiro-idp-server-.claude-skills-spec-security --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Hirokazu Kobayashi Koba Hiro Idp Server .Claude Skills Spec Security?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aibot88-hirokazu-kobayashi-koba-hiro-idp-server-claude-ski)More formats (shields.io, HTML) on the badges page.
---
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 | DB検索優先化 |
| 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 |
---
## 認証識別子切り替え攻撃(CWE-287)
### 攻撃シナリオ
```
1. 被害者のメールアドレスAで認証開始
2. チャレンジ送信後、攻撃者メールアドレスBに変更
3. Bの検証コードで認証
4. 【脆弱】: メールアドレスAとしてログイン ❌
5. 【正常】: メールアドレスBとしてログイン ✅
```
### 対策コード
`EmailAuthenticationInteractor.java:257-306`:
```java
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
```
---
## Redirect URI切り替え攻撃(CWE-601)
### 攻撃シナリオ
| 攻撃パターン | 説明 | 対策 |
|-------------|------|------|
| Token Endpoint不一致 | 認可時と異なるredirect_uriでトークン取得 | 完全一致検証 |
| 未登録URI | 登録されていないredirect_uriを使用 | 登録URI必須 |
| 部分一致攻撃 | `example.com/callback.evil.com` | 厳密一致(substring禁止) |
| URIエンコーディング | `%2e%2e/` でパストラバーサル | 正規化後検証 |
### RFC 6749 準拠検証
```java
// 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件)**:
- Token Endpoint redirect_uri検証
- 未登録URI拒否
- 部分一致攻撃防止
- HTTP/HTTPS スキーム違い検証
- ポート省略/明示検証
- クエリパラメータ追加検証
- 認可コード再利用防止
---
## Session Fixation(CWE-384)
### 攻撃シナリオ
```
1. 攻撃者がSession IDを取得
2. 被害者に固定Session IDでアクセスさせる
3. 被害者が認証完了
4. 【脆弱】: 攻撃者が同じSession IDで被害者としてアクセス ❌
5. 【正常】: 認証後にSession ID再生成 ✅
```
### 対策
認証成功後にセッションを再生成し、旧セッションIDを無効化。
### セキュリティテスト
```
e2e/src/tests/security/session_fixation_password_auth.test.js
```
---
## 認可コード再利用攻撃(CWE-294)
### RFC 6749 Section 10.5
> "The authorization server MUST ensure that authorization codes cannot be used more than once."
### 対策コード
`AuthorizationCodeGrantService.java:131-134, 202`:
```java
// 存在確認
if (!authorizationCodeGrant.exists()) {
throw new TokenBadRequestException("invalid_grant", "not found authorization code.");
}
// ... トークン発行処理 ...
// 使用後は即時削除(再利用防止)
authorizationCodeGrantRepository.delete(tenant, authorizationCodeGrant);
```
---
## マルチテナント分離(CWE-284)
### 設計原則
```java
// ✅ 全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); // 危険
}
```
### Row-Level Security(PostgreSQL)
```sql
-- 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
```
---
## SSRF保護(CWE-918)
### ブロック対象(16種)
`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`:
```java
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` スキル参照。
---
## Null Byte Injection(CWE-626)
### 攻撃シナリオ
```
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を一括防御:
- **Query parameters / form-urlencoded body**: `getParameterNames()` / `getParameterValues()` でチェック
- **JSON/その他のリクエストボディ**: InputStreamを先読みしてバイト列をスキャン
- **リクエストボディサイズ制限**: 10MB超のJSONボディを413 Payload Too Largeで拒否
- Null byte検出時: 400 Bad Request + ERRORレベルセキュリティログ出力
```java
@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 |
- 本番ではAWS API Gatewayが10MBで先に弾く
- フィルターはAPI Gatewayがない環境やバイパスされた場合のdefense-in-depth
- nginxは20MBに設定し、E2Eテストでフィルターの413を直接検証可能にしている
### セキュリティテスト
```
e2e/src/tests/spec/malicious_request_reject_filter.test.js
```
**テストケース(5件)**:
- CIBA binding_message に null byte
- CIBA scope に null byte
- CIBA login_hint に null byte
- Token grant_type に null byte
- 10MB超のJSONボディで413 Payload Too Large
---
## ユーザーステータス検証
### 無効ユーザーの認可防止
```
e2e/src/tests/security/invalid_user_status_authorization.test.js
```
---
## セキュリティテスト実行
### 全セキュリティテスト
```bash
cd e2e
npm test -- security/
```
### 個別実行
```bash
# 認証識別子切り替え
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"
```
---
## セキュリティテスト作成パターン
```javascript
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参照
| 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` | テスト実行方法 |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!