보안 개요
1. 인증 / 인가
JWT 기반 인증 흐름
로그인 요청 → AuthenticationProvider 인증
→ JWT Access Token + Refresh Token 발급
→ 이후 요청 시 Authorization: Bearer {token} 헤더 포함
→ JwtFilter가 토큰 검증 → SecurityContext 설정
| 항목 | 값 (권장) |
| 알고리즘 | HS512 |
| Access Token 유효시간 | 10~30분 |
| Refresh Token 유효시간 | 30분~7일 (앱 자동 로그인 시 최대 60일) |
| 토큰 저장 위치 | HttpOnly 쿠키 또는 메모리 (localStorage 금지) |
Spring Security 설정 기본
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable) // JWT 사용 시 CSRF 비활성화
.sessionManagement(sm ->
sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
2. 비밀번호 정책
| 항목 | 권장값 |
| 최대 로그인 실패 횟수 | 5회 초과 시 계정 잠금 |
| 관리자 미접속 제한 | 30일 경과 시 계정 잠금 |
| 일반 사용자 미접속 제한 | 서비스 성격에 따라 결정 |
| 비밀번호 변경 주기 | 90일 (만료 시 재설정 유도) |
| 비밀번호 최소 조건 | 8자 이상, 영문·숫자·특수문자 조합 |
// BCrypt 해시 적용
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
3. XSS 방어
입력값 이스케이프
// XSS 필터: HttpServletRequestWrapper 래핑
public class XssRequestWrapper extends HttpServletRequestWrapper {
@Override
public String getParameter(String name) {
return StringEscapeUtils.escapeHtml4(super.getParameter(name));
}
}
Content Security Policy
// Nginx 또는 Spring Security 헤더 설정
http.headers(h -> h
.contentSecurityPolicy(csp ->
csp.policyDirectives("default-src 'self'; script-src 'self'"))
);
4. SQL Injection 방어
- MyBatis
#{} 파라미터 바인딩 사용 (${} 사용 금지 — 불가피한 경우 화이트리스트 검증)
- 동적 쿼리는
<if>, <where>, <foreach> 태그 활용
<!-- 안전 -->
WHERE USER_ID = #{userId}
<!-- 위험: SQL Injection 가능 -->
WHERE USER_ID = '${userId}'
5. CSRF 방어
| 인증 방식 | CSRF 처리 |
| JWT (Stateless) | csrf().disable() — 세션 없으므로 불필요 |
| 세션 기반 (Stateful) | Spring Security CSRF 토큰 활성화 필수 |
6. CORS 설정
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://{서비스도메인}")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
allowedOrigins("*")와 allowCredentials(true) 동시 사용 불가.
7. 민감 정보 관리
| 항목 | 처리 방법 |
| DB 비밀번호, API 키 | 환경변수 또는 Jasypt ENC(...) 암호화 |
| JWT Secret | 환경변수 주입 (32자 이상 랜덤 문자열) |
| 운영 서버 민감값 | AWS Secrets Manager 또는 Jenkins Credentials |
.env 파일 | git 커밋 제외 (.gitignore 필수) |
8. 보안 헤더
Nginx 또는 Spring Security로 보안 헤더를 추가한다.
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Referrer-Policy "strict-origin-when-cross-origin";
관련 문서
security/nginx-security-headers.md — Nginx 보안 헤더 상세 설정
security/spring-exception-handling.md — 인증 예외 처리
security/nginx-rate-limiting.md — Nginx 요청 빈도 제한
setup/jasypt-encryption.md — Jasypt YML 암호화