1. Default Security Headers
Spring Security는 기본적으로 보안에 관련된 HTTP Response Header를 제공합니다.
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-XSS-Protection: 0
2. Cache Control
기본 캐싱 전략
- Spring Security는 기본적으로 사용자의 내용을 보호하기 위해 캐싱을 비활성화 합니다.
- 악의적인 공격자가 로그아웃 후 뒤로가기 버튼으로 사용자의 민감정보를 보지 못하게 하려는 것입니다.
기본 캐시 제어 헤더
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
- 브라우저에게 해당 페이지나 리소스를 캐시하지 말라고 지시합니다.
사용자 정의 캐시 제어 헤더
- 하지만 만약 애플리케이션에서 캐시 제어 헤더를 제공한다면 Spring Security는 사용자 정의 헤더를 우선시합니다.
- 이런 전략은 정적 리소스가 캐시되는데 주로 사용됩니다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.cacheControl(cache -> cache.disable())
);
return http.build();
}
}
3. Content Type Options
content-sniff
- 브라우저가 응답의 Content-Type을 추론하는 기능입니다.
- 브라우저는 Body 부분을 읽어 추론합니다
- 과거에는 브라우저에서 정확한 Content-Type을 얻기 위해 사용하였습니다.
- 올바르지 않은 Content-Type 값이 전달되는 경우에 대한 방법입니다.
문제점
- 악의적인 사용자의 XSS 공격에 노출될 수 있습니다.
- HTTP Request의 Body 에 악의적인 스크립트를 작성하여 요청하면 서버는 해당 스크립트를 읽게 됩니다.
해결책
X-Content-Type-Options: nosniff
- 기본적으로 Spring Security는 XSS 공격의 노출을 피하기 위해 no-sniff 설정으로 응답헤더를 제공합니다.
- Content-Type도 올바르게 작성되어야 정상적으로 요청이 인식됩니다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
);
return http.build();
}
}
4. HTTP Strict Transport Security (HSTS)
- 모든 요청이 HTTPS 프로토콜로 이루어져야 함을 강제하는 보안 헤더입니다.
- 중간자 공격을 방지하기 위해 사용됩니다. (Man-in-the-Middle attack)
- HTTP 요청은 리다이렉션되어 HTTPS 프로토콜로 재요청 됩니다.
- 옵션을 사용하여 서버는 브라우저에게 추가적인 HTTPS 프로토콜 사용을 알릴 수 있습니다.
적용 조건
- 브라우저는 내장된 신뢰할 만한 CA 리스트를 통해 서버의 SSL 인증서가 유효한지 확인합니다.
- 해당 서버의 SSL 인증서가 자신의 CA 화이트리스트에 포함되어있는지 확인합니다.
- HSTS 헤더는 HTTPS 응답에만 삽입됩니다.
적용 방법
- 브라우저의 HSTS preload 리스트에 호스트를 등록합니다.
- 응답에 Strict-Transport-Security 헤더를 추가합니다.
기본 설정
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- 브라우저에 도메인을 1년간 HSTS 호스트로 취급하도록 지시합니다
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.preload(true)
.maxAgeInSeconds(31536000)
)
);
return http.build();
}
}
옵션 지시자
- includeSubDomains : 브라우저에게 '서브도메인도 HSTS 도메인으로 취급함'을 지시합니다.
- preload : 브라우저에 해당 도메인이 HSTS 도메인으로 미리 로드되어야 함을 지시합니다.
5. X-Frame-Options
- 브라우저가 embedded 페이지 태그의 렌더링을 막는 응답헤더입니다.
- 웹사이트에 프레임이 있는것이 보안 이슈를 발생시킬 수 있습니다.
Clickjacking
- 자신의 의도가 아닌 클릭으로 공격자가 만들어둔 로직이 동작하여 피해를 입는 공격패턴
- CSS style을 현란하게 해서 사용자가 의도치않게 특정 컴포넌트를 클릭하게 하여 피해가 발생함
- 로그인된 사용자가 버튼을 눌러 이체 권한을 공격자에게 부여하도록 함
방어법
- CSP (Content Security Policy)
- X-Frame-Options
- DENY : 모든 frame 태그 사용 금지
- SAMEORIGIN : 현재 페이지와 같은 origin으로 이동하는 frame 태그만 허용
- ALLOW-FROM (origin) : 특정 origin으로 이동하는 frame 태그만 허용
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.frameOptions(frameOptions -> frameOptions
.sameOrigin()
)
);
return http.build();
}
}
6. X-XSS-Protection
- 페이지 로딩중 XSS 공격을 감지하는 보안 헤더입니다.
- 취약점으로 인해 최신 브라우저에서 지원하지 않습니다. (CSP 사용 권장)
X-XSS-Protection: 0
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.xssProtection(xss -> xss
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
)
);
return http.build();
}
}
7. Content Security Policy
- 브라우저가 특정 리소스를 로드하거나 실행할 수 있는 규칙을 정의하는 응답헤더
- 브라우저에게 웹 애플리케이션이 로드할것으로 예상되는 소스에 대한 정보를 제공합니다.
- 추가적인 보안 레이어를 두는 효과를 주어 웹 관련 공격을 방어하는데 효과적입니다.
Content-Security-Policy
Content-Security-Policy: script-src https://trustedscripts.example.com
Content-Security-Policy: script-src https://trustedscripts.example.com; report-uri /csp-report-endpoint/
- script-src : 스크립트를 로드할 수 있는 화이트리스트를 지정하는 지시어
- report-url : 보안정책 위반을 보고할 uri를 지정하는 지시어
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
)
);
return http.build();
}
}
Content-Security-Policy-Report-Only
- 웹 애플리케이션 작성자와 관리자가 보안 정책을 강제하는 대신 모니터링할 수 있도록 하는 기능을 제공합니다.
- 보안 정책에 위반되는 리소스 로드 시도가 발생하면, 이러한 시도는 차단되지 않고 브라우저는 해당 위반에 대한 보고만 생성합니다
Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.example.com; report-uri /csp-report-endpoint/
8. Referrer Policy
- 웹 애플리케이션에서 사용자의 이전 페이지 정보를 포함하고 있는 "referrer" 필드를 관리하는 메커니즘입니다.
- 브라우저가 리소스나 페이지를 요청할 때 Referer 헤더에 포함할 URL의 일부 또는 전체를 결정하는 방법을 지정하는 데 사용됩니다.
- 사용자가 이전에 있던 페이지(출처) 정보를 목적지 웹사이트나 페이지에 알리도록 브라우저에 지시합니다.
Referer header
- 해당 요청을 생성한 URL을 포함하는 헤더입니다.
- 로깅, 캐시 최적화, 보안등의 목적으로 사용됩니다.
정책
- same-origin
- 같은 출처의 요청에 대해서만 전체 경로를 Referer 헤더에 포함합니다.
- 다른 출처로의 요청에는 Referer 헤더를 전송하지 않습니다.
- strict-origin
- 같은 출처나 다른 출처에 상관없이 origin만 Referer 헤더에 포함합니다.
- HTTPS에서 HTTP로의 요청 시 Referer 헤더를 전송하지 않습니다.
- strict-origin-when-cross-origin
- 같은 출처의 요청에 대해서는 전체 URL을 포함합니다.
- 다른 출처로의 요청에는 오리진만 포함합니다.
- HTTPS에서 HTTP로의 요청에 대해서는 Referer 헤더를 전송하지 않습니다.
- origin-when-cross-origin
- 같은 출처의 요청에 대해서는 전체 URL을 포함합니다.
- 다른 출처로의 요청에 대해서는 오리진만 포함합니다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.referrerPolicy(referrer -> referrer
.policy(ReferrerPolicy.SAME_ORIGIN)
)
);
return http.build();
}
}
9. Custom Headers
Static Headers
- 변하지 않는 고정된 값을 가진 HTTP 헤더를 의미합니다
- 사용자 정의 헤더는 어플리케이션 내에서 특정 기능이나 정보를 전달하기 위해 사용될 수 있습니다.
- 일반적으로 "X-" 접두어는 비표준 또는 사용자 정의 헤더를 나타내는 데 사용됩니다.
- 예를 들면, 특정 보안 정책이나 사용자의 세션 정보, 요청에 대한 추가 정보 등을 포함할 수 있습니다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
);
return http.build();
}
}
Headers Writer
- 사용자는 사용자 정의 HeadersWriter 인스턴스를 생성하거나 HeadersWriter의 사용자 정의 구현을 제공할 수 있습니다
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
);
return http.build();
}
}
DelegatingRequestMatcherHeaderWriter
- 특정 조건에 맞는 요청에만 HTTP 헤더를 추가하고 싶을 때의 상황을 설명합니다.
- DelegatingRequestMatcherHeaderWriter는 특정 요청에 대해서만 헤더를 작성하는 기능을 제공합니다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
RequestMatcher matcher = new AntPathRequestMatcher("/login");
DelegatingRequestMatcherHeaderWriter headerWriter =
new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
http
// ...
.headers(headers -> headers
.frameOptions(frameOptions -> frameOptions.disable())
.addHeaderWriter(headerWriter)
);
return http.build();
}
}
출처
'Spring > Spring Security' 카테고리의 다른 글
[Spring Security] 4-4. 보안: HttpFirewall (0) | 2023.10.14 |
---|---|
[Spring Security] 4-3. 보안: HTTP (0) | 2023.10.14 |
[Spring Security] 4-1. 보안: CSRF (0) | 2023.10.06 |
[Spring Security][KoLiving] 4-5. BlackList Token (0) | 2023.10.03 |
[Spring Security][KoLiving] 4-4. RefreshToken Rotation (0) | 2023.10.03 |