機能は実装できる。では「法規制を満たし、安全に使ってもらう」ために Web 基盤に何を実装し、どこまでやれば安心と言えるのか ——OWASP ASVS 5.0 のレベル2 を安心ラインに、3省2ガイドラインと検査業務の要件を、Java(Spring)・Angular の実装例で示す。
本資料は 2026 年 5 月時点の一般整理。実装例は方針を示すもので、実際の採用にあたっては各バージョンの公式ドキュメントと自組織のセキュリティ方針で検証すること。OWASP ASVS は 5.0.0(2025年5月)を参照。
OWASP ASVS(Application Security Verification Standard)5.0 は、Web アプリのセキュリティ要件を 17 章・約 350 項目に整理したチェックリスト。リスクに応じた 3 段階のレベルがある。
| 姿勢 | 評価 |
|---|---|
| 機能が動いたら完了 | 不足。認証・監査・データ保護の実装が抜け、法規制違反・漏えいリスクが残る。 |
| 全項目を L3 まで | 過剰。コストと工数が膨らみ、現場の開発が回らない。 |
| 要配慮コアは L2(一部 L3)、周辺は L1〜L2 | 現実解。患者の検査データを扱う中核機能に L2 を確実に、リスクの高い箇所だけ L3 を足す。 |
| カテゴリ | 主な実装 | 紐づく法規制・ASVS章 |
|---|---|---|
| 認証・セッション・認可 | 二要素認証、セッションタイムアウト、RBAC、データ単位認可 | 3省2GL運用編14章 / ASVS V6,V7,V8 |
| 入力・出力・Web | 入力検証、SQLi/XSS/CSRF 対策 | 安全管理措置 / ASVS V1,V2,V3,V4 |
| 暗号・データ保護・通信 | フィールド暗号化、マスキング、TLS 強制 | 個情法23条 / ASVS V11,V12,V14 |
| ログ・API・設定・依存 | 監査ログ、API 認証、依存脆弱性管理、秘密情報管理 | 3省2GL / 事業者向けGL / ASVS V13,V15,V16 |
| 検査業務特有 | 精度管理記録、トレーサビリティ、結果確定・訂正履歴、届出連携 | 検体検査精度確保 / 感染症法 |
// Spring Security 6.4+ の組み込みパスキー(WebAuthn)または TOTP
// 物理区画(検査室)運用なら ICカード+生体で「二要素相当」も可
http.webAuthn(w -> w.rpName("LIS").rpId("lis.example.jp")
.allowedOrigins("https://lis.example.jp"));
Angular
// WebAuthn は navigator.credentials.create/get を使用
// MFA 入力画面は通常のフォーム + ワンタイムコード検証 API 呼び出し
@Bean PasswordEncoder encoder() {
return new BCryptPasswordEncoder(12); // または Argon2PasswordEncoder
}
// 推定不可・運用担当者もパスワードを復元できない(3省2GL 14章⑥)
// AuthenticationFailureHandler で失敗回数を記録、閾値でロック
// アカウント列挙を防ぐため、エラーメッセージは一律にするserver.servlet.session.timeout=15m # アイドルタイムアウト
# Angular 側でも操作監視 → 一定時間で自動ログアウト + 警告ダイアログhttp.sessionManagement(s -> s.sessionFixation().newSession());
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true
server.servlet.session.cookie.same-site=strict@PreAuthorize("hasRole('TECHNOLOGIST')")
public Result confirmResult(Long id) { ... }
// メソッドセキュリティを有効化:@EnableMethodSecurity@PreAuthorize("hasRole('DOCTOR') and @resultPolicy.canConfirm(#id, principal)")
// 代行入力は actor(操作者)と subject(責任者)を別々に記録// id だけでなく「その利用者がアクセスしてよいか」を where 句に含める
repo.findByIdAndDepartment(id, currentUser.getDepartment())
.orElseThrow(AccessDeniedException::new);// Bean Validation
public record OrderReq(@NotNull Long patientId, @Size(max=50) String memo) {}
@PostMapping void create(@Valid @RequestBody OrderReq r) { ... }
// SQLi 対策:JPA / @Query はパラメータバインド。文字列連結は禁止
@Query("select r from Result r where r.code = :code")
// Angular は {{ }} 補間とプロパティバインドで自動エスケープ
// 危険:bypassSecurityTrustHtml() の安易な使用は禁止
// HTML を表示するなら DomSanitizer で必ずサニタイズ
// Spring Security は CSRF 保護がデフォルト有効
// SPA は CookieCsrfTokenRepository でトークンを Cookie 配布
Angular// provideHttpClient(withXsrfConfiguration({
// cookieName: 'XSRF-TOKEN', headerName: 'X-XSRF-TOKEN' }))
// XSRF-TOKEN Cookie を読み X-XSRF-TOKEN ヘッダで自動送信
// 外部リクエスト先は許可リストで限定(任意URL禁止)
// アップロードは MIME・拡張子・サイズ検証 + ウイルススキャン
// 状態遷移は enum + ガード条件でサーバ検証// JPA AttributeConverter でフィールド暗号化(AES-GCM)
@Convert(converter = EncryptedStringConverter.class)
private String diagnosis;
// 鍵は KMS / Secrets Manager 管理。コードにハードコードしない// ログ出力時に PII をマスクするフィルタ(logback)
// 患者 ID は URL クエリでなくパス or ボディ、ログにはハッシュ/連番// AES-256-GCM 等の標準アルゴリズム。鍵は AWS KMS / CloudHSM
// 自前で暗号方式を発明しない(標準ライブラリを使う)http.requiresChannel(c -> c.anyRequest().requiresSecure());
http.headers(h -> h.httpStrictTransportSecurity(hsts -> hsts.maxAgeInSeconds(31536000)));// AOP @Around または HandlerInterceptor で操作を記録
// 構造化ログ(JSON)+ MDC で相関ID。actor / action / patientRef / timestamp
// ログは改ざん防止(S3 Object Lock 等の WORM 保管へ転送)@ControllerAdvice + @ExceptionHandler で一律のエラー応答
server.error.include-stacktrace=never
server.error.include-message=never # 本番// OAuth2 Resource Server(JWT 検証)
http.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()));
// レート制限:Resilience4j / API Gateway
// レスポンスは DTO で必要項目だけ返す(エンティティ直返し禁止)// OWASP Dependency-Check(Maven/Gradle plugin)/ Snyk を CI に組込み
// AWS Inspector で SBOM(CycloneDX/SPDX)出力// セキュリティヘッダー:CSP, X-Frame-Options, X-Content-Type-Options
http.headers(h -> h.contentSecurityPolicy(c -> c.policyDirectives("default-src 'self'")));
// 秘密情報は Secrets Manager / 環境変数。application.yml に平文で書かない// ヘルスチェック(liveness/readiness):Spring Boot Actuator
// グレースフルシャットダウン:server.shutdown=graceful
// 再送に耐える冪等性(重複オーダー防止):冪等キー + 一意制約
// 依存先障害のタイムアウト・サーキットブレーカー:Resilience4j
// ログ・記録は保存年限(診療録5年 等)をライフサイクルで管理
本シリーズは、医療情報システムの開発・クラウド化を手がける X Harumi が、公的な一次資料を根拠条項まで遡って再整理したものです。AI 活用支援・業務効率化・DX 推進・システム開発を提供しています。