Swagger IP 접근 제한 처리
문제점
Swagger의 접근을 서버의 IP와 swagger url만 알게 된다면, 모두가 접근할 수 있었습니다.
서버 보안에 대해서 생각을 잘 못하고 있다가 한번 패스워드가 누군가에 의해 변경되는 사고를 겪고 나서 보안에 대해서 더욱 공부를 많이 하고 할 수 있는 보안 처리는 모두 하자라는 생각이 들었습니다. 그래서 스웨거의 접근에 대해서 고민을 하게 되었고, Swagger를 접근할 수 있는 IP를 설정하였습니다.
해결 방안
1. Spring Security를 사용 시, hasIpAddress(’’)으로 허용할 IP를 설정
SpEL은 Spring Expression Language의 약자로, Spring Framework에서 제공하는 표현식 언어
- 속성 접근, 메서드 호출, 조건문 등 다양한 기능 제공
- Spring Security, Spring Data JPA, Spring ELK 등 다양한 Spring 모듈에서 사용 가능
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/swagger-ui/**", "/v3/api-docs/**")
.access("hasIpAddress('192.0.0.1')") // SpEL (Spring Expression Language)
.anyRequests().permitAll()
.and()
.csrf().disable();
}
}
2. Filter를 통해서 IP 설정
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String clientIp = httpServletRequest.getRemoteAddr();
// Swagger URL에 대한 IP 제한
String requestUri = httpServletRequest.getRequestURI();
if ((requestUri.startsWith("/swagger-ui") || requestUri.startsWith("/v3/api-docs")) && !ALLOWED_IP.equals(clientIp)) {
log.error("허용되지 않는 IP입니다.");
throw new SecurityException("허용되지 않는 IP입니다.");
}
chain.doFilter(request, response);
}
3. interceptor으로 ip 허용

- 디스패치 서블릿이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조 또는 가공
```
@Component
public class SwaggerInterceptor implements HandlerInterceptor {
private static final String ALLOWED_IP = "192.168.1.100"; // 허용할 IP
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String clientIp = getClientIp(request);
if (ALLOWED_IP.equals(clientIp)) {
return true; // 허용된 IP면 요청 진행
}
response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403 Forbidden
response.getWriter().write("Access Denied");
return false; // 요청 차단
}
private String getClientIp(HttpServletRequest request) {
String clientIp = request.getHeader("X-Forwarded-For");
if (clientIp == null || clientIp.isEmpty()) {
clientIp = request.getRemoteAddr();
}
return clientIp;
}
}
```
4. proxy 서버에서의 설정(ex. nginx)
location /swagger-ui {
allow 192.168.1.100; # 허용할 IP
deny all; # 다른 IP는 차단
}
location /v3/api-docs {
allow 192.168.1.100; # 허용할 IP
deny all; # 다른 IP는 차단
}
5. Swagger Config 파일에서 설정
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.enable(isSwaggerEnabled());
}
private boolean isSwaggerEnabled() {
String allowedIp = "192.168.1.100";
String clientIp = getClientIp();
return allowedIp.equals(clientIp);
}
private String getClientIp() {
// IP 가져오는 로직 구현 필요
return "192.168.1.100"; // 예시
}
}
변경 점
저는 다양한 방법 중에서 2번을 선택하기로 했습니다.
리팩토링하면서 중요하게 본 것이 실제 서버에게 영향을 최대한 주지 않으면서 할 수 있는 방법은 무언인가 생각했습니다.
1번 제외 이유
Spring Expression Language 을 사용하는 것은 너무 생소하기도 하고, 설정이 잘 안 되어서 포기한 부분이었습니다.
3번 제외 이유
Interceptort은 DispatcherServlet 이후에 동작하기 때문에 Spring 내부 로직에 진입한 이후에 실행되어서 IP 접근 제한은 Filter로 작성하는 것이 더 적절하다고 생각이 들었습니다.
4번 제외 이유
실 서버에서 nginx을 사용하여 proxy가 작동되고 있지만, nginx 설정 파일을 건들여야 하고 재시작을 해야 한다는 점이 리스크가 발생할 수 있다고 생각이 들어 4번은 제외 대상이 되었습니다.
5번 제외 이유
Config 파일은 서버가 실행될 때 한 번 실행되기 때문에, 로그를 추적할 수 없습니다. 저는 여기에 접속한 IP가 무엇인지 추적하고 싶었습니다. 그래서 제외 대상이 되었습니다.
추가 설정
fail2ban을 설정 했습니다.fail2ban이란 로그 파일을 스캔하여, 로그인 시도를 많이 실패하는 IP 주소를 차단하는 프로그램입니다.
/var/log/auth.log을 필터링하여 ssh 접속을 감시합니다.

사진을 보면 무차별적인 접속이 오는 것을 알 수 있습니다.
느낀 점
제가 백엔드 개발자임에 불구하고, 보안 쪽에 너무 모르고 있었지 않나 생각이 듭니다. 개발할 때, 보안 측면에서 생각하는 노력을 키워야겠다는 생각이 듭니다. 물론, 보안 프로그램이 존재한다면 좋겠지만 없는 데로 제가 할 수 있는 것을 해야만 한다고 생각합니다. 다음에는 부족한 부분을 다른 방식으로 어떻게 해결할 수 있는가에 대해서 더욱 고민해 보는 노력을 해야겠습니다.
'Project > 회사프로젝트' 카테고리의 다른 글
| Android AGP 버전 업그레이드 (0) | 2026.03.25 |
|---|---|
| 프로젝트 리팩토링: 아키텍처 (0) | 2024.11.27 |