【プログラミング】【java】Spring Security - j-komatsu/myCheatSheet GitHub Wiki
DevSecOps(Development, Security, Operations)は、開発プロセスにセキュリティを統合するアプローチです。
項目 | 説明 |
---|---|
シフトレフト(Shift Left) | 開発の早い段階でセキュリティを適用 |
自動化テスト | セキュリティテスト(SAST, DAST, SCA)を CI/CD に組み込む |
コンテナセキュリティ | Docker イメージの脆弱性スキャンを実施 |
ゼロトラスト | 認証・認可を常に検証し、信頼せず監視 |
DevSecOps(Development, Security, Operations)は、開発プロセスにセキュリティを統合するアプローチです。
項目 | 説明 |
---|---|
シフトレフト(Shift Left) | 開発の早い段階でセキュリティを適用 |
自動化テスト | セキュリティテスト(SAST, DAST, SCA)を CI/CD に組み込む |
コンテナセキュリティ | Docker イメージの脆弱性スキャンを実施 |
ゼロトラスト | 認証・認可を常に検証し、信頼せず監視 |
Spring Security(スプリング セキュリティ)は、Spring Frameworkを基盤としたアプリケーションの認証と認可を管理するセキュリティフレームワークです。
特徴 | 説明 |
---|---|
認証(Authentication) | ユーザーのIDとパスワードを検証する |
認可(Authorization) | ユーザーがどのリソースにアクセスできるか制御する |
カスタマイズ性 | フィルターやカスタム認証などを独自実装可能 |
Springとの統合 | Spring Bootと連携し、簡単に導入できる |
まず、Spring Securityを利用するために、以下の依存関係を pom.xml
に追加します。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Bootでは、デフォルトで全てのエンドポイントが保護され、Basic認証が有効になります。
spring:
security:
user:
name: admin
password: secret
この設定をすると、デフォルトのBasic認証で admin / secret
でログインできます。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin()
.and()
.httpBasic();
return http.build();
}
}
Mermaid.jsを使って、Spring Securityのリクエストフローを図示します。
sequenceDiagram
participant User
participant Browser
participant SpringSecurity
participant Server
User->>Browser: アクセス要求
Browser->>SpringSecurity: 認証情報を送信
SpringSecurity->>Server: 認証情報チェック
Server->>SpringSecurity: 認証結果を返す
SpringSecurity->>Browser: 認可チェック
Browser->>User: 成功ならコンテンツを表示
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if ("user".equals(username)) {
return User.withUsername(username)
.password(new BCryptPasswordEncoder().encode("password"))
.roles("USER")
.build();
}
throw new UsernameNotFoundException("User not found");
}
}
@Component
public class CustomAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 認証処理
filterChain.doFilter(request, response);
}
}
- 認証(Authentication) → 入店するための「予約確認」
- 認可(Authorization) → 「予約あり」かどうか、VIP席が必要かの判断
- フィルター(Filter) → 入り口のスタッフが服装チェックをする
Spring Securityは、認証と認可の管理を行う強力なフレームワークです。
設定を変更すれば、Basic認証、フォーム認証、JWT認証など様々な認証方法を実装できます。
📌 次のステップ
- フォームログインとOAuth認証の設定
- JWTを用いた認証の実装
Spring Security で フォームログイン を設定するには、以下のように HttpSecurity
をカスタマイズします。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login") // カスタムログインページの指定
.permitAll()
)
.logout(logout -> logout.permitAll());
return http.build();
}
}
@Controller
public class LoginController {
@GetMapping("/login")
public String showLoginPage() {
return "login"; // login.html を表示
}
}
<form method="post" action="/login">
<input type="text" name="username" placeholder="ユーザー名" required>
<input type="password" name="password" placeholder="パスワード" required>
<button type="submit">ログイン</button>
</form>
Spring Security で OAuth2 ログインを実装するには、 spring-boot-starter-oauth2-client
を追加します。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.oauth2Login(); // OAuth2ログインを有効化
return http.build();
}
}
spring:
security:
oauth2:
client:
registration:
google:
client-id: {GoogleのクライアントID}
client-secret: {Googleのクライアントシークレット}
この設定により、Google の OAuth2 認証を利用できるようになります。
JWT(JSON Web Token)は、クライアントとサーバー間の認証情報をトークンとして管理する方式です。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.11.5</version>
</dependency>
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import javax.crypto.SecretKey;
public class JwtUtil {
private static final SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1日
.signWith(key)
.compact();
}
public static Jws<Claims> validateToken(String token) {
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
}
}
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
try {
Jws<Claims> claims = JwtUtil.validateToken(token);
String username = claims.getBody().getSubject();
// 認証成功時の処理
} catch (JwtException e) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
filterChain.doFilter(request, response);
}
}
- フォームログイン: HTMLフォームを利用した一般的な認証
- OAuth2認証: Googleなどの外部サービスを用いた認証
- JWT認証: トークンベースのセキュアな認証
📌 次のステップ
- 認可(Authorization)設定の詳細
- RBAC(ロールベースアクセス制御)の実装
認可(Authorization)は、ユーザーがどのリソースにアクセスできるかを制御する仕組み です。 Spring Security では、URL・メソッドレベル・ロールベースなど様々な認可方式を提供します。
Spring Security では、HttpSecurity
を使用してURL単位でアクセス制御が可能です。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN") // 管理者のみ許可
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN") // ユーザーと管理者許可
.anyRequest().authenticated()
)
.formLogin()
.and()
.logout();
return http.build();
}
}
-
/admin/**
は ADMIN ロールのユーザー のみアクセス可能 -
/user/**
は USER または ADMIN のユーザーがアクセス可能 - それ以外のエンドポイントは 認証済みのユーザーのみ 許可
Spring Security では、アノテーションを使ってメソッド単位でアクセス制御が可能です。
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// 管理者のみ削除可能
}
}
@Secured("ROLE_ADMIN")
public void updateUser(Long userId) {
// 管理者のみ更新可能
}
@RolesAllowed({"ROLE_USER", "ROLE_ADMIN"})
public void viewUser(Long userId) {
// ユーザーまたは管理者が実行可能
}
RBAC(Role-Based Access Control)は、ユーザーの役割(ロール)に応じてアクセス権を付与する方式です。
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@ElementCollection(fetch = FetchType.EAGER)
private List<String> roles;
}
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRoles().toArray(new String[0]))
.build();
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.formLogin()
.and()
.logout();
return http.build();
}
}
-
URLベース認可 →
authorizeHttpRequests()
を使ってアクセス制御 -
メソッドレベル認可 →
@PreAuthorize
などのアノテーションで制御 - RBAC(ロールベースアクセス制御) → ユーザーのロールに応じた認可
📌 次のステップ
- Spring Security のカスタム認証プロバイダ
- 多要素認証(MFA)の実装
Spring Security の カスタム認証プロバイダ(AuthenticationProvider) は、独自の認証ロジックを実装するための仕組みです。
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
if ("user".equals(username) && "password".equals(password)) {
return new UsernamePasswordAuthenticationToken(username, password, List.of(new SimpleGrantedAuthority("ROLE_USER")));
} else {
throw new BadCredentialsException("Invalid credentials");
}
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.authenticationProvider(customAuthenticationProvider)
.build();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin();
return http.build();
}
}
多要素認証(MFA, Multi-Factor Authentication)は、パスワード + 追加の認証要素(OTP、SMS認証など) を組み合わせてセキュリティを強化する方式です。
(1) Google Authenticatorを使う場合のライブラリ追加
<dependency>
<groupId>com.warrenstrange</groupId>
<artifactId>googleauth</artifactId>
<version>1.4.0</version>
</dependency>
(2) OTPの生成ロジック
import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
@Service
public class OtpService {
private final GoogleAuthenticator gAuth = new GoogleAuthenticator();
public String generateSecretKey() {
GoogleAuthenticatorKey key = gAuth.createCredentials();
return key.getKey();
}
public boolean verifyCode(String secretKey, int code) {
return gAuth.authorize(secretKey, code);
}
}
(3) MFAの認証フロー
@RestController
@RequestMapping("/mfa")
public class MfaController {
@Autowired
private OtpService otpService;
private final Map<String, String> userSecrets = new HashMap<>();
@PostMapping("/generate")
public String generateMfaKey(@RequestParam String username) {
String secretKey = otpService.generateSecretKey();
userSecrets.put(username, secretKey);
return "Secret Key: " + secretKey;
}
@PostMapping("/verify")
public ResponseEntity<String> verifyMfa(@RequestParam String username, @RequestParam int otp) {
String secretKey = userSecrets.get(username);
if (secretKey != null && otpService.verifyCode(secretKey, otp)) {
return ResponseEntity.ok("MFA 認証成功");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("MFA 認証失敗");
}
}
}
- カスタム認証プロバイダ を実装し、独自の認証ロジックを追加可能
- MFA(多要素認証) を導入し、OTP認証を組み合わせてセキュリティを強化
📌 次のステップ
- セッション管理とRemember-Me認証
- CORS設定とセキュリティヘッダーのカスタマイズ
Spring Security では、セッション管理 をカスタマイズすることで、セッション固定攻撃の防止や同時ログインの制御が可能です。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 必要に応じてセッションを作成
.maximumSessions(1) // 同時ログインを1つに制限
.expiredUrl("/session-expired") // セッションが切れた場合のリダイレクト先
)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.logout();
return http.build();
}
}
-
SessionCreationPolicy.IF_REQUIRED
:必要に応じてセッションを作成 -
maximumSessions(1)
:同じアカウントでの同時ログインを1つに制限 -
expiredUrl("/session-expired")
:セッションが切れた際のリダイレクト先を指定
Remember-Me(記憶ログイン)は、ユーザーがブラウザを閉じた後もログイン状態を保持できる機能です。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.rememberMe(remember -> remember
.key("uniqueAndSecret") // キーの指定
.tokenValiditySeconds(86400) // 1日(24時間)
)
.logout();
return http.build();
}
}
-
key("uniqueAndSecret")
:Remember-Me用のキーを設定 -
tokenValiditySeconds(86400)
:トークンの有効期間を24時間に設定
CORS(Cross-Origin Resource Sharing)は、異なるオリジン間でのリクエストを制御する仕組みです。
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:3000", "https://example.com")); // 許可するオリジン
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); // 許可するHTTPメソッド
config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
-
setAllowedOrigins()
:許可するオリジンを指定 -
setAllowedMethods()
:許可するHTTPメソッドを指定 -
setAllowedHeaders()
:リクエストで送信可能なヘッダーを指定 -
setAllowCredentials(true)
:クレデンシャル(認証情報)の送信を許可
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(Customizer.withDefaults()) // CORSを有効化
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.logout();
return http.build();
}
}
Spring Security は、デフォルトで様々なセキュリティヘッダー を有効化しています。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.headers(headers -> headers
.contentSecurityPolicy("default-src 'self'") // Content Security Policy (CSP)
.xssProtection(xss -> xss.block(true)) // XSS 対策
.frameOptions(frame -> frame.deny()) // iframeの利用を禁止
)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.logout();
return http.build();
}
}
-
contentSecurityPolicy("default-src 'self'")
:外部スクリプトの実行を制限 -
xssProtection(xss -> xss.block(true))
:XSS対策を有効化 -
frameOptions(frame -> frame.deny())
:クリックジャッキング攻撃を防ぐためiframe
を禁止
- セッション管理 → 同時ログイン制御やセッション固定攻撃の防止
- Remember-Me認証 → ログイン状態を維持
- CORS設定 → フロントエンドとバックエンド間の通信制御
- セキュリティヘッダー → XSS対策やクリックジャッキング防止
📌 次のステップ
- API セキュリティ(Rate Limiting、CSRF対策)
- WebSocket でのセキュリティ対策
APIを安全に保つためには、Rate Limiting(リクエスト制限)や CSRF 対策 が重要です。
Spring Boot で Rate Limiting を実装するには、Bucket4j
や Spring Boot Resilience4j
などのライブラリを使用できます。
(1) 依存関係を追加
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>8.0.0</version>
</dependency>
(2) レート制限を適用するフィルターを作成
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Refill;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
@Component
public class RateLimitingFilter implements Filter {
private final Bucket bucket;
public RateLimitingFilter() {
this.bucket = Bucket.builder()
.addLimit(Bandwidth.classic(5, Refill.intervally(5, Duration.ofMinutes(1))))
.build();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (bucket.tryConsume(1)) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).sendError(HttpServletResponse.SC_TOO_MANY_REQUESTS, "Too many requests");
}
}
}
- 1分間に5回までのリクエストを許可
- 超過すると
429 Too Many Requests
を返す
Spring Security では、CSRF保護 がデフォルトで有効になっています。API では通常 stateless
設定を使用するため、CSRFを無効化するケースもあります。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // APIの場合は無効化(トークン認証を使用するため)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.logout();
return http.build();
}
}
💡 推奨: CSRFトークンを活用する場合、csrfTokenRepository()
を設定できます。
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
- CSRF トークンを Cookie に保存 し、リクエスト時に送信
WebSocket では、認証・認可 の設定が重要です。
@Configuration
@EnableWebSecurity
public class WebSocketSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.csrf(csrf -> csrf.ignoringRequestMatchers("/ws/**")); // WebSocket の場合は CSRF 無効化
return http.build();
}
}
@Component
public class AuthenticatedWebSocketHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Authentication authentication = (Authentication) session.getPrincipal();
if (authentication == null || !authentication.isAuthenticated()) {
session.close(CloseStatus.NOT_ACCEPTABLE);
}
}
}
@Configuration
@EnableWebSocketSecurity
public class WebSocketSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.requestMatchers("/ws/**").hasRole("USER"))
.formLogin();
return http.build();
}
}
/ws/**
の WebSocket エンドポイントにROLE_USER
を持つユーザーのみアクセス可能
-
Rate Limiting(レート制限) →
Bucket4j
を利用してリクエスト制限 -
CSRF対策 →
CookieCsrfTokenRepository
を活用する or API の場合は無効化 - WebSocket のセキュリティ → 認証・認可の適用
📌 次のステップ
- OAuth2.0 + JWT を使った認証・認可
- クラウド環境での Spring Security のベストプラクティス
クラウド環境では、セキュリティを強化するために以下のポイントが重要です。
項目 | 説明 |
---|---|
環境変数の活用 | 認証情報や秘密鍵を環境変数で管理する |
HTTPS の強制 | クラウドのリバースプロキシ経由で HTTPS を適用する |
OAuth2.0 & JWT | クラウド環境での分散認証管理に適用する |
CORS の適切な設定 | フロントエンドとバックエンド間のセキュアな通信を確保 |
API Gateway の利用 | セキュリティポリシーを一元管理する |
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
💡 ポイント:
-
GOOGLE_CLIENT_ID
やGOOGLE_CLIENT_SECRET
は環境変数で管理し、直接ハードコードしない。
クラウド環境では、リバースプロキシ(Nginx, AWS ALB など)を使用し、HTTPS を適用する。
(1) Spring Security で HTTP → HTTPS リダイレクトを適用
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.requiresChannel(channel -> channel.anyRequest().requiresSecure()) // HTTPS を強制
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.logout();
return http.build();
}
}
クラウド環境では、API Gateway(AWS API Gateway, Azure API Management など)を利用することで、認証管理を一元化できます。
AWS API Gateway で JWT 認証を適用する例:
- Cognito や Auth0 を使用し、JWT を発行
-
Authorization
ヘッダーを API Gateway で検証
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
💡 ポイント:
- API Gateway で JWT の検証を行い、Spring Security 側での認証負荷を軽減。
クラウド環境では、CORS を適切に設定することで、セキュアな通信を確保できます。
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://frontend.example.com")); // 許可するオリジン
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
💡 ポイント:
- 許可するオリジンを制限し、オープンな CORS 設定を避ける。
- 環境変数を活用 して認証情報を管理
- HTTPS を強制 し、セキュアな通信を確保
- API Gateway を活用 して認証負荷を軽減
- CORS 設定を適切に してフロントエンドと安全に接続
📌 次のステップ
- Kubernetes 環境での Spring Security の管理
- Serverless(AWS Lambda, Azure Functions)でのセキュリティ対策
Kubernetes で Spring Security を適用する際、以下のポイントに注意する必要があります。
項目 | 説明 |
---|---|
Secret 管理 | 環境変数や Kubernetes Secrets を活用する |
Ingress での HTTPS 強制 | Ingress Controller を活用し HTTPS を適用する |
OAuth2.0 & JWT | 分散環境での認証・認可を実装する |
Pod 内のセキュリティ | RBAC や Network Policy でアクセス制御を行う |
Kubernetes では、Secret
を利用して機密情報(API キー、JWT 秘密鍵など)を管理します。
echo -n "my-secret-value" | base64
kubectl create secret generic my-secret --from-literal=jwt-secret=my-secret-value
spring:
security:
jwt:
secret: ${JWT_SECRET}
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-app
spec:
template:
spec:
containers:
- name: spring-app
env:
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: my-secret
key: jwt-secret
💡 ポイント:
- Kubernetes Secrets を利用し、環境変数として Spring Boot に注入。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spring-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: spring-app
port:
number: 8080
💡 ポイント:
- Ingress Controller を使い、HTTPS リダイレクトを適用。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list"]
💡 ポイント:
- RBAC(Role-Based Access Control)で Kubernetes リソースのアクセス制御を実施。
Serverless 環境(AWS Lambda, Azure Functions)では、Spring Security を適用する際の考慮点が異なります。
AWS API Gateway で JWT 認証を適用する場合、Cognito や Auth0 を使用します。
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
💡 ポイント:
- API Gateway で JWT の検証を行い、Lambda での負荷を軽減。
public class LambdaHandler {
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) {
String token = event.getHeaders().get("Authorization");
if (JwtUtil.validateToken(token)) {
return new APIGatewayProxyResponseEvent().withStatusCode(200).withBody("認証成功");
} else {
return new APIGatewayProxyResponseEvent().withStatusCode(401).withBody("認証失敗");
}
}
}
Azure Functions では、Managed Identity や Function Keys を活用してセキュリティを強化します。
authLevel: function
identity:
type: SystemAssigned
💡 ポイント:
- Managed Identity を利用し、Azure AD 認証を適用。
- Kubernetes では Secret, RBAC, Ingress を活用し、セキュリティを強化
- AWS Lambda では API Gateway + JWT を組み合わせて認証を実装
- Azure Functions では Managed Identity を活用し、アクセス管理を強化
📌 次のステップ
- マイクロサービス環境における Spring Security の適用
- Istio / Service Mesh との統合によるセキュリティ強化
マイクロサービス環境では、各サービス間の認証・認可を適切に管理することが重要です。
セキュリティ要件 | 方式 |
---|---|
サービス間認証 | OAuth2.0 + JWT を使用 |
API Gateway の活用 | 認証処理を API Gateway にオフロード |
RBAC(ロールベースアクセス制御) | 各サービスごとにロールを適用 |
トランスポートレイヤーの保護 | HTTPS + mTLS(Istio など) |
マイクロサービスごとに JWT を検証し、認可を適用します。
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/token")
public String generateToken(@RequestParam String username) {
return JwtUtil.generateToken(username);
}
}
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
try {
Jws<Claims> claims = JwtUtil.validateToken(token);
String username = claims.getBody().getSubject();
// 認証成功時の処理
} catch (JwtException e) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
filterChain.doFilter(request, response);
}
}
💡 ポイント:
- 認証は ユーザーサービス に集約し、他のサービスは JWT を検証 するだけにする。
API Gateway(Spring Cloud Gateway, Kong, AWS API Gateway など)を使用し、認証を一元化。
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://user-service:8080
predicates:
- Path=/users/**
filters:
- AuthenticationFilter
💡 ポイント:
- API Gateway で JWT の認証を行い、各マイクロサービスの負荷を軽減
Service Mesh(Istio, Linkerd など)を活用し、サービス間の通信を保護。
Istio の PeerAuthentication
を使い、mTLS を適用。
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
💡 ポイント:
- mTLS を適用し、サービス間通信を暗号化
Istio では、JWT の検証を Envoy Proxy で実施可能。
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: default
spec:
selector:
matchLabels:
app: user-service
jwtRules:
- issuer: "https://auth.example.com"
jwksUri: "https://auth.example.com/.well-known/jwks.json"
💡 ポイント:
- 各マイクロサービスの JWT 検証を Istio にオフロード
- マイクロサービス環境では OAuth2.0 + JWT を活用
- API Gateway で認証を一元化し、各サービスの負荷を軽減
- Istio を活用し、mTLS + JWT 認証を適用
📌 次のステップ
- Zero Trust Architecture(ゼロトラスト)の実装
- セキュリティ監視とログ管理のベストプラクティス
ゼロトラストアーキテクチャ(Zero Trust Architecture, ZTA)は、「信頼しない、常に検証する」という原則に基づき、ネットワークの内外を問わず、すべてのリクエストを検証するセキュリティモデルです。
原則 | 説明 |
---|---|
最小権限の原則(Least Privilege) | 必要最小限の権限のみを付与する |
継続的な認証・検証(Continuous Authentication) | ユーザーやデバイスの認証を継続的に実施 |
マイクロセグメンテーション | ネットワークを細かく分割し、サービスごとにアクセス制御 |
暗号化の徹底 | 通信・データをすべて暗号化 |
リアルタイムの監視とログ管理 | すべてのアクティビティを記録し、異常検知を行う |
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin()
.and()
.sessionManagement(session -> session.sessionFixation().migrateSession())
.logout();
return http.build();
}
}
- MFA(多要素認証)を適用 し、認証の強度を向上。
- セッション固定攻撃対策(Session Fixation Protection)を適用
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: default
spec:
mtls:
mode: STRICT
- mTLS を適用し、サービス間の通信を暗号化
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
@PreAuthorize("hasRole('ADMIN')")
public void adminOnlyAction() {
// 管理者専用のアクション
}
}
- ユーザーのロールに基づいた認可を適用
セキュリティを強化するためには、ログ管理と異常検知が不可欠です。
監視ポイント | 説明 |
---|---|
認証ログ | ログイン・ログアウトの成功・失敗記録 |
API アクセスログ | 誰が・いつ・どのエンドポイントを利用したか |
異常検知 | 短時間に多数のログイン失敗が発生した場合のアラート |
監査ログ | 重要な管理操作の記録(ユーザー作成・権限変更など) |
@Component
public class AuthenticationLogger implements ApplicationListener<AuthenticationSuccessEvent> {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationLogger.class);
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
logger.info("User {} logged in successfully", event.getAuthentication().getName());
}
}
@Component
public class AuthenticationFailureLogger implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationFailureLogger.class);
@Override
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
logger.warn("Failed login attempt for user: {}", event.getAuthentication().getName());
}
}
- 成功・失敗のログインイベントを記録し、不正アクセスを監視
ツール | 説明 |
---|---|
ELK Stack (Elasticsearch, Logstash, Kibana) | ログの収集・分析・可視化 |
Prometheus + Grafana | メトリクス監視とアラート設定 |
AWS CloudWatch / Azure Monitor | クラウド環境でのログ監視 |
SIEM(Security Information and Event Management) | セキュリティイベントの統合監視 |
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "spring-security-logs"
}
}
- Logstash を使い、Spring Security のログを Elasticsearch に転送
scrape_configs:
- job_name: 'spring-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['spring-app:8080']
- Spring Boot Actuator と連携し、メトリクスを可視化
- Zero Trust Architecture(ゼロトラスト)を適用し、認証・認可を強化
- ログ管理と監視ツールを組み合わせ、異常検知を自動化
- ELK / Prometheus / SIEM などのツールを活用し、セキュリティを可視化
📌 次のステップ
- AI を活用したセキュリティ異常検知
- 脅威インテリジェンス(Threat Intelligence)との連携
AI を活用した異常検知(Anomaly Detection)は、セキュリティの脅威を自動的に分析し、リアルタイムでアラートを発する仕組みです。
手法 | 説明 |
---|---|
機械学習(ML)ベースのログ分析 | ユーザー行動のパターンを学習し、不審なアクティビティを検出 |
リアルタイム異常検知(Streaming Analytics) | Kafka や Flink を活用し、リアルタイムでログ分析 |
自動インシデント対応(SOAR) | AI を活用し、異常が発生した際に自動的に対策を実行 |
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "security-logs"
}
}
- Elasticsearch にログを保存し、Kibana の Machine Learning モジュールで分析
import pandas as pd
from sklearn.ensemble import IsolationForest
# ログデータをロード
log_data = pd.read_csv("security_logs.csv")
# 特徴量の選択(例:ログイン試行回数)
X = log_data[["failed_login_attempts", "login_time"]]
# Isolation Forest で異常検知
model = IsolationForest(contamination=0.05)
log_data["anomaly"] = model.fit_predict(X)
# 異常が検出されたログを表示
print(log_data[log_data["anomaly"] == -1])
- Isolation Forest を活用し、異常なログイン試行を検出
- 異常が検出された場合、アラートを発生
脅威インテリジェンスとは、最新のセキュリティ脅威情報(IP、ドメイン、マルウェアシグネチャなど)を活用し、リアルタイムで攻撃を防御する仕組みです。
方法 | 説明 |
---|---|
既知の悪意のある IP / ドメインのブロック | Threat Intelligence フィードを活用し、攻撃元をブロック |
YARA ルールによるマルウェア検知 | マルウェアのパターンを定義し、ファイルスキャンを実施 |
SIEM(Security Information and Event Management)連携 | SIEM を活用し、脅威をリアルタイム分析 |
@Component
public class IpBlacklistFilter extends OncePerRequestFilter {
private static final Set<String> BLACKLISTED_IPS = Set.of("192.168.1.100", "203.0.113.45");
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String ipAddress = request.getRemoteAddr();
if (BLACKLISTED_IPS.contains(ipAddress)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
return;
}
filterChain.doFilter(request, response);
}
}
- ブラックリストに登録された IP からのアクセスを拒否
import requests
API_KEY = "your_api_key"
IP_ADDRESS = "203.0.113.45"
response = requests.get(
f"https://api.xforce.ibmcloud.com/ipr/{IP_ADDRESS}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
if response.json().get("score", 0) > 5:
print("High risk IP detected! Blocking request.")
- IBM X-Force Exchange などの脅威インテリジェンス API を活用し、リスクの高い IP をブロック
- AI を活用してセキュリティログを分析し、異常を検知
- 機械学習モデルを利用して、不審なログインや API アクセスを識別
- 脅威インテリジェンスを活用し、既知の悪意のある IP やマルウェアをブロック
📌 次のステップ
- DevSecOps における Spring Security の適用
- セキュアな CI/CD パイプラインの構築
DevSecOps(Development, Security, Operations)は、開発プロセスにセキュリティを統合するアプローチです。
項目 | 説明 |
---|---|
シフトレフト(Shift Left) | 開発の早い段階でセキュリティを適用 |
自動化テスト | セキュリティテスト(SAST, DAST, SCA)を CI/CD に組み込む |
コンテナセキュリティ | Docker イメージの脆弱性スキャンを実施 |
ゼロトラスト | 認証・認可を常に検証し、信頼せず監視 |
name: SAST Scan
on:
push:
branches:
- main
jobs:
sast:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Run SonarQube Scan
uses: sonarsource/[email protected]
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- SonarQube を利用して、コードの静的解析を自動化
name: DAST Scan
on:
push:
branches:
- main
jobs:
dast:
runs-on: ubuntu-latest
steps:
- name: Run OWASP ZAP Scan
uses: zaproxy/[email protected]
with:
target: "https://example.com"
- OWASP ZAP を利用して、アプリケーションの脆弱性を動的に検査
name: Dependency Scan
on:
push:
branches:
- main
jobs:
dependency_scan:
runs-on: ubuntu-latest
steps:
- name: Run Snyk Scan
uses: snyk/actions/maven@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- Snyk を使用して、依存ライブラリの脆弱性をスキャン
ステージ | セキュリティ対策 |
---|---|
コードコミット | SAST(静的解析)を実施 |
ビルド | 依存関係の脆弱性スキャン(SCA) |
デプロイ前 | DAST(動的解析)を実施 |
デプロイ後 | ログ監視とアラート通知 |
name: Secure CI/CD Pipeline
on:
push:
branches:
- main
jobs:
security_checks:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Run SAST Scan
uses: sonarsource/[email protected]
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Run Dependency Scan
uses: snyk/actions/maven@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Run DAST Scan
uses: zaproxy/[email protected]
with:
target: "https://example.com"
name: Container Security Scan
on:
push:
branches:
- main
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Scan Docker Image
uses: aquasecurity/trivy-action@master
with:
image-ref: "my-app:latest"
- Trivy を使って Docker イメージの脆弱性をスキャン
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: falco
spec:
template:
spec:
containers:
- name: falco
image: falcosecurity/falco
securityContext:
privileged: true
- Falco を活用し、コンテナのリアルタイム監視を実施
- DevSecOps では、SAST, DAST, SCA を組み合わせ、開発の早い段階でセキュリティを適用
- CI/CD パイプラインにセキュリティチェックを統合し、自動化
- コンテナ環境では、Trivy や Falco で脆弱性スキャンとランタイム監視を実施
📌 次のステップ
- クラウドネイティブセキュリティのベストプラクティス
- AI を活用した DevSecOps の最適化
coming soon