0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IPA「安全なウェブサイトの作り方」の11項目に基づいたチェックリスト+サイドチャネル対策チェックリスト

0
Last updated at Posted at 2026-05-02

Security レポート

本プロジェクト(Spring Boot バックエンド + React フロントエンド + Supabase 認証/DB)について、IPA「安全なウェブサイトの作り方」の11項目に基づきセキュリティ実装状況を整理したものです。

調査日: 2026-05-02
対象ブランチ: main


総合判定サマリー

# 脆弱性 判定 対応概要
1.1 SQLインジェクション ✅ 対策済 JdbcClient のパラメータバインディング
1.2 OSコマンド・インジェクション ➖ 該当なし OSコマンド実行処理なし
1.3 ディレクトリ・トラバーサル ➖ 該当なし ファイルアップロード/ダウンロードなし
1.4 セッション管理 ✅ 対策済 JWT + HttpOnly Cookie + SameSite + Stateless
1.5 XSS ✅ 対策済 React 自動エスケープ + JSON API
1.6 CSRF ✅ 対策済 CSRF トークン + SameSite + login/logout/refresh で検証
1.7 HTTPヘッダ・インジェクション ✅ 対策済 リダイレクト処理なし + HSTS / X-Content-Type-Options / Referrer-Policy 設定
1.8 メールヘッダ・インジェクション ➖ 該当なし メール送信機能なし
1.9 クリックジャッキング ✅ 対策済 X-Frame-Options: DENY + CSP frame-ancestors 'none'
1.10 バッファオーバーフロー ➖ 該当なし Java/JVM 環境
1.11 アクセス制御・認可制御 ✅ 対策済 ロール別制御 + IDOR チェック + Supabase RLS
補足 サイドチャネル対策 (Spectre 等) ✅ 対策済 COOP same-origin + Sec-Fetch-Site 検証フィルタ

詳細

1.1 SQLインジェクション ✅

対策内容:

  • すべてのSQL操作で JdbcClient (Spring Framework) を使用し、プレースホルダ + パラメータバインディングで実装。
  • ユーザー入力のSQL文字列連結は存在しない。
  • ILIKE 検索でも likeQuery パラメータでバインド済み。

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/repository/StudentRepository.java
  • backend/src/main/java/com/example/studentmanagement/repository/AttendanceRepository.java
  • backend/src/main/java/com/example/studentmanagement/repository/DashboardRepository.java
// 例: StudentRepository.java
.param("studentCode", request.studentCode())

1.2 OSコマンド・インジェクション ➖

Runtime.exec() / ProcessBuilder の使用なし。該当する攻撃面が存在しない。


1.3 ディレクトリ・トラバーサル ➖

ファイルアップロード/ダウンロード機能なし。パス操作は UUID ベースの ID のみで動的パス構築なし。


1.4 セッション管理 ✅

対策内容:

  • JWT (Supabase Auth) ベースの認証。
  • Spring Security は Stateless 構成。
  • ログイン時にアクセストークン + リフレッシュトークン発行、/api/auth/refresh で更新可能。
  • ログアウト時に Supabase API 呼び出し + 全認証クッキー削除。
  • Cookie 属性:
    • HttpOnly=true
    • Secure=設定可 (環境変数 APP_AUTH_COOKIE_SECURE)
    • SameSite=Lax
    • リフレッシュトークンは Path=/api/auth/refresh に限定

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/security/AuthCookieService.java:71-75
  • backend/src/main/java/com/example/studentmanagement/config/SecurityConfig.java:48 (SessionCreationPolicy.STATELESS)
  • backend/src/main/java/com/example/studentmanagement/controller/AuthController.java:58-83

1.5 XSS ✅

対策内容:

  • フロントは React JSX による自動 HTML エスケープ。
  • dangerouslySetInnerHTML / innerHTML の使用なし。
  • バックエンドは JSON API 専用 (application/json;charset=UTF-8)。
  • 入力値は react-hook-form + zod でバリデーション。

根拠ファイル:

  • frontend/src/pages/LoginPage.tsx
  • frontend/src/pages/StudentDetailPage.tsx
  • backend/src/main/java/com/example/studentmanagement/config/SecurityConfig.java:66

1.6 CSRF ✅

対策内容:

  • Spring Security の CookieCsrfTokenRepository.withHttpOnlyFalse() でトークン発行 (XSRF-TOKEN クッキー)。
  • /api/auth/csrf で初期トークン取得用エンドポイント。
  • フロントは X-XSRF-TOKEN ヘッダで自動送信 (http.ts)。
  • CSRF 検証対象を /api/auth/login, /logout, /refresh に明示。
  • SameSite=Lax Cookie でクロスサイト送信を制限。

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/config/SecurityConfig.java:79-86
  • backend/src/main/java/com/example/studentmanagement/controller/AuthController.java:95-103
  • frontend/src/lib/api/http.ts:44-98

1.7 HTTPヘッダ・インジェクション ✅

対策内容:

  • 動的リダイレクト処理がないため Location ヘッダ経由の攻撃面はない。
  • 追加防御として以下のセキュリティヘッダを SecurityConfig.headers(...) で配信:
    • Strict-Transport-Security: max-age=31536000; includeSubDomains (HTTPS リクエストのみ)
    • X-Content-Type-Options: nosniff
    • Referrer-Policy: strict-origin-when-cross-origin

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/config/SecurityConfig.java:52-66

1.8 メールヘッダ・インジェクション ➖

メール送信機能なし。@Email バリデーションは入力検証のみ。


1.9 クリックジャッキング ✅

対策内容:

  • X-Frame-Options: DENY を全レスポンスに付与(旧ブラウザ互換)。
  • Content-Security-Policy: default-src 'none'; frame-ancestors 'none' を全レスポンスに付与(モダンブラウザ準拠)。
  • API は JSON 専用のため default-src 'none' でも副作用なし。
  • iframe 埋め込みは完全禁止。

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/config/SecurityConfig.java:52-66

1.10 バッファオーバーフロー ➖

Java/JVM 環境のためメモリ安全性は言語レベルで担保。


1.11 アクセス制御・認可制御 ✅

対策内容:

  • ロール定義: ADMIN / TEACHER / STAFF (StaffRole.java)
  • 各 Service 層で明示的な権限チェック:
    • 生徒登録: admin のみ
    • 生徒更新: admin、または teacher(担当生徒のみ)
    • 生徒削除: admin のみ
  • IDOR 対策: teacherCanAccessStudent() で teacher の担当外生徒アクセスを拒否。
  • Supabase RLS との連携: RlsContextService で JWT claims を PostgreSQL セッション変数に伝搬し、DB レベルでも権限チェック。
  • フロントは ProtectedRouteallowedRoles をチェック。

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/service/StudentService.java:52-83
  • backend/src/main/java/com/example/studentmanagement/repository/StudentRepository.java:183-199
  • backend/src/main/java/com/example/studentmanagement/security/RlsContextService.java
  • frontend/src/components/layout/ProtectedRoute.tsx:25-29

その他

パスワードハッシュ化 ✅

Supabase Auth に委譲(bcrypt + salt)。アプリ側で平文パスワードを保持しない。

CORS ⚠️

  • allowedOrigins はホワイトリスト方式 (APP_CORS_ALLOWED_ORIGINS 環境変数)。
  • allowCredentials=true
  • ⚠️ allowedHeaders=List.of("*") のため、必要最低限に絞ることを推奨。

環境変数による本番/開発切り替え ✅

  • application.yml.env 読み込み + デフォルト値。
  • 本番では APP_AUTH_COOKIE_SECURE=true, APP_CORS_ALLOWED_ORIGINS=https://... を設定する想定。

サイドチャネル対策 (Spectre 等) ✅

対策内容:

  • Cross-Origin-Opener-Policy: same-origin を全レスポンスに付与し、tabnabbing と cross-window のサイドチャネルを抑制。
  • FetchMetadataFilter/api/** への状態変更リクエスト (POST/PUT/PATCH/DELETE) について Sec-Fetch-Site を検証し、same-origin / same-site / none 以外なら 403 で拒否。CSRF トークンと多重防御を構成。
  • Sec-Fetch-Mode: navigate のトップレベル遷移は除外し、ヘッダ未送信の旧クライアントは通過(CSRF トークンで防御)。
  • COEP は外部リソース連携への副作用を避けるため意図的に未対応とした。

根拠ファイル:

  • backend/src/main/java/com/example/studentmanagement/config/SecurityConfig.java:65-66, 80
  • backend/src/main/java/com/example/studentmanagement/security/FetchMetadataFilter.java

補足: 配信されるセキュリティヘッダ一覧

ヘッダ 目的
X-Frame-Options DENY クリックジャッキング
Content-Security-Policy default-src 'none'; frame-ancestors 'none' XSS 緩和 / クリックジャッキング
Strict-Transport-Security max-age=31536000; includeSubDomains HTTPS 強制 (HTTPS リクエスト時のみ)
X-Content-Type-Options nosniff MIME スニッフィング抑制
Referrer-Policy strict-origin-when-cross-origin リファラ漏洩防止
Cross-Origin-Opener-Policy same-origin cross-window サイドチャネル対策


次回使える Security チェックリスト

新規プロジェクトや機能追加時に、本プロジェクトで実施した対策を再現するためのチェックリストです。

認証・セッション

  • 認証方式を決定(JWT / セッション / OAuth など)
  • パスワードは外部認証サービス or bcrypt 等でハッシュ化(平文保持禁止)
  • Spring Security を SessionCreationPolicy.STATELESS で構成(JWT 採用時)
  • アクセストークン + リフレッシュトークンの 2 段構成
  • ログイン後にセッション ID(またはトークン)を再発行
  • ログアウト時に全認証クッキーをクリア + 外部認証サービスのログアウト API 呼び出し
  • 認証 Cookie に HttpOnly=true
  • 認証 Cookie に Secure=true(本番環境)— 環境変数で開発時は false 切替
  • 認証 Cookie に SameSite=Lax 以上
  • リフレッシュトークン Cookie の Path/api/auth/refresh 等に限定
  • アクセス/リフレッシュトークンの有効期限を設定(例: refresh 30日)
  • フロント側で 401 時の自動リトライ実装(http.ts

CSRF

  • CookieCsrfTokenRepository.withHttpOnlyFalse() でトークン発行
  • XSRF-TOKEN Cookie に SameSite=Lax
  • CSRF 検証対象を明示的に列挙(/api/auth/login, /logout, /refresh など)
  • CSRF トークン取得用エンドポイント(/api/auth/csrf)の用意
  • フロント側で X-XSRF-TOKEN ヘッダを自動付与(GET/HEAD/OPTIONS/TRACE 除く)
  • フロント初回ロード時に CSRF トークンを取得する仕組み

SQL インジェクション

  • JdbcClient / JdbcTemplate / JPA / MyBatis のパラメータバインディング使用
  • SQL の文字列連結は禁止(コードレビューで確認)
  • LIKE / ILIKE 検索もパラメータバインドで実装
  • DB ユーザー権限を最小限に絞る
  • エラーメッセージで SQL 文や DB 構造を露出しない

XSS

  • フロントは React/Vue 等の自動エスケープ付きフレームワーク採用
  • dangerouslySetInnerHTML / v-html / innerHTML の使用禁止
  • バックは JSON API 形式(Content-Type: application/json;charset=UTF-8
  • 入力バリデーションを zod + react-hook-form(フロント)と @Valid + @NotBlank 等(バック)で二重実装
  • エラーレスポンスも JSON で返却し、HTML 埋め込みしない

認可制御(IDOR 対策含む)

  • ロール定義(例: ADMIN / TEACHER / STAFF
  • 各エンドポイントで「ログイン済み」だけでなく「権限があるか」を確認
  • Service 層で明示的な権限チェック(Controller だけに任せない)
  • リソース所有者チェック(teacher は担当生徒のみ等)
  • DB レベルでも RLS 等で多重防御(Supabase RLS、PostgreSQL ポリシー)
  • JWT claims を DB セッション変数へ伝搬する仕組み(RlsContextService 相当)
  • フロントの ProtectedRouteallowedRoles チェック
  • 動的 SQL のロール別分岐ロジックを Repository に実装
  • テストで他人 ID へのアクセスが 403 になることを確認

CORS

  • allowedOrigins をホワイトリスト方式(* 禁止)
  • allowCredentials=true 時はオリジンを必ず限定
  • allowedMethods を必要なメソッドのみに絞る
  • allowedHeaders を必要なヘッダのみに絞る(* を避ける)
  • 環境変数 (APP_CORS_ALLOWED_ORIGINS 等) で本番/開発を切り替え

セッション管理(Cookie 詳細)

  • HttpOnly / Secure / SameSite を全認証 Cookie に設定
  • Cookie の Path 属性で送信範囲を限定
  • Cookie の Max-Age / Expires を適切に設定
  • 開発環境向け Cookie 設定の上書き機構(環境変数)

セキュリティヘッダ(本プロジェクト実装済)

  • X-Frame-Options: DENY(または SAMEORIGIN / CSP frame-ancestors で代替)
  • Content-Security-Policy 設定(API 専用なら default-src 'none'; frame-ancestors 'none'
  • Strict-Transport-Security (HSTS) — HTTPS 環境で
  • X-Content-Type-Options: nosniff
  • Referrer-Policy: strict-origin-when-cross-origin
  • Cross-Origin-Opener-Policy: same-origin(Spectre 系サイドチャネル対策)
  • Cross-Origin-Embedder-Policy: require-corp — 外部リソース利用時は副作用注意(本プロジェクトは未採用)
  • Cross-Origin-Resource-Policy — COEP とセットで検討
  • Permissions-Policy — 利用ブラウザ機能を絞りたい場合に設定

実装ポイント:

  • Spring Security 6 系では http.headers(headers -> headers.frameOptions(...).contentSecurityPolicy(...).httpStrictTransportSecurity(...)) で一括設定可能。
  • frameOptions(frame -> frame.disable()) + addHeaderWriter(new XFrameOptionsHeaderWriter(DENY)) のパターンで SAMEORIGIN デフォルトを上書き。
  • HSTS は HTTPS リクエスト時のみ送出されるため、ローカル HTTP 開発を阻害しない。

Fetch Metadata 検証

  • /api/** の状態変更リクエスト (POST/PUT/PATCH/DELETE) で Sec-Fetch-Site を検証
  • same-origin / same-site / none のいずれかのみ通過、それ以外は 403 拒否
  • Sec-Fetch-Mode: navigate のトップレベル遷移は除外
  • ヘッダ未送信の旧ブラウザ・curl 等は通過(CSRF トークンで防御)
  • レスポンスは {"code":"FORBIDDEN","message":"..."} JSON 形式で統一
  • CSRF フィルタより前段に挿入し、cross-site リクエストを早期遮断

環境変数・設定管理

  • .env.gitignore に登録
  • 本番/開発切替を環境変数で制御(application.yml のデフォルト値 + override)
  • Supabase ANON_KEY / JWT_ISSUER などの秘匿情報を環境変数化
  • 本番デプロイ時に Cookie Secure や CORS Origin が正しく上書きされることを確認

エラーハンドリング・ログ

  • 統一的な ApiExceptionHandler で 401/403/400/500 を JSON で返却
  • エラーメッセージで内部実装(テーブル名、スタックトレース)を露出しない
  • 認証失敗・権限エラーは構造化ログに記録
  • 機密情報(パスワード、トークン)をログに出力しない

ファイル操作(該当時)

  • ファイル名やパスをユーザー入力から直接構築しない
  • アップロード先ディレクトリを固定 + ファイル名を UUID 等で再生成
  • パス正規化後にベースディレクトリ配下か確認
  • アップロードサイズ・拡張子の制限

OS コマンド実行(該当時)

  • 可能な限り使用しない(ライブラリ API で代替)
  • 引数は配列形式で渡す(シェル経由を避ける)
  • 入力値はホワイトリスト検証

メール送信(該当時)

  • メール送信ライブラリ(Spring Boot Starter Mail 等)を使用
  • Subject / From / To に改行文字を許可しない
  • 送信先はアプリ側で制御(ユーザー入力で送信先を決めない)

デプロイ前最終チェック

  • 本番環境で HTTPS 強制
  • APP_AUTH_COOKIE_SECURE=true
  • APP_CORS_ALLOWED_ORIGINS が本番ドメインに設定
  • Supabase RLS ポリシーが有効
  • OS / ミドルウェア / 依存ライブラリが最新
  • gradle dependencyUpdates 等で脆弱な依存がないか確認
  • npm audit でフロント依存の脆弱性確認
  • バックアップ・ロールバック手順の整備
  • インシデント対応手順の整備
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?