- HeaderWriterFilter
- 현재 응답(Response)에 헤더(Headers)를 추가하는 Filter 구현체.
- 브라우저 보안을 활성화하는 특정 헤더를 추가하는 데 유용할 수 있음.
- Ex) 다음과 같은 보안 헤더를 추가할 수 있음.
- X-Frame-Options
- 클릭재킹(Clickjacking) 공격 방지.
- X-XSS-Protection
- X-Content-Type-Options
package org.springframework.security.web.header;
import java.io.IOException;
import java.util.List;
import jakarta.servlet.FilterChain;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.web.util.OnCommittedResponseWrapper;
import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;
public class HeaderWriterFilter extends OncePerRequestFilter {
private final List<HeaderWriter> headerWriters;
private boolean shouldWriteHeadersEagerly = false;
public HeaderWriterFilter(List<HeaderWriter> headerWriters) {
Assert.notEmpty(headerWriters, "headerWriters cannot be null or empty");
this.headerWriters = headerWriters;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.shouldWriteHeadersEagerly) {
doHeadersBefore(request, response, filterChain);
}
else {
doHeadersAfter(request, response, filterChain);
}
}
private void doHeadersBefore(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
writeHeaders(request, response);
filterChain.doFilter(request, response);
}
private void doHeadersAfter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse(request, response);
HeaderWriterRequest headerWriterRequest = new HeaderWriterRequest(request, headerWriterResponse);
try {
filterChain.doFilter(headerWriterRequest, headerWriterResponse);
}
finally {
headerWriterResponse.writeHeaders();
}
}
void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
for (HeaderWriter writer : this.headerWriters) {
writer.writeHeaders(request, response);
}
}
public void setShouldWriteHeadersEagerly(boolean shouldWriteHeadersEagerly) {
this.shouldWriteHeadersEagerly = shouldWriteHeadersEagerly;
}
class HeaderWriterResponse extends OnCommittedResponseWrapper {
private final HttpServletRequest request;
HeaderWriterResponse(HttpServletRequest request, HttpServletResponse response) {
super(response);
this.request = request;
}
@Override
protected void onResponseCommitted() {
writeHeaders();
this.disableOnResponseCommitted();
}
protected void writeHeaders() {
if (isDisableOnResponseCommitted()) {
return;
}
HeaderWriterFilter.this.writeHeaders(this.request, getHttpResponse());
}
private HttpServletResponse getHttpResponse() {
return (HttpServletResponse) getResponse();
}
}
static class HeaderWriterRequest extends HttpServletRequestWrapper {
private final HeaderWriterResponse response;
HeaderWriterRequest(HttpServletRequest request, HeaderWriterResponse response) {
super(request);
this.response = response;
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
return new HeaderWriterRequestDispatcher(super.getRequestDispatcher(path), this.response);
}
}
static class HeaderWriterRequestDispatcher implements RequestDispatcher {
private final RequestDispatcher delegate;
private final HeaderWriterResponse response;
HeaderWriterRequestDispatcher(RequestDispatcher delegate, HeaderWriterResponse response) {
this.delegate = delegate;
this.response = response;
}
@Override
public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
this.delegate.forward(request, response);
}
@Override
public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException {
this.response.onResponseCommitted();
this.delegate.include(request, response);
}
}
}
private boolean shouldWriteHeadersEagerly = false;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.shouldWriteHeadersEagerly) {
doHeadersBefore(request, response, filterChain);
}
else {
doHeadersAfter(request, response, filterChain);
}
}
- 헤더를 추가하는 방식은 2가지(요청을 처리하기 전에 헤더를 추가 or 요청을 처리한 후에 헤더를 추가)로 나뉘는데 현재 기본값이
false로 설정되어 있어서 요청을 처리한 후에 헤더를 추가함.