왜
AdminAccessFilter.shouldNotFilter 가 게이트 적용 여부를 raw request.requestURI 로 판정하는데, Spring 은 디코딩·정규화된 경로로 라우팅한다. 그래서 /admin 을 다르게 표기하면 게이트만 건너뛰고 컨트롤러에는 그대로 도달한다.
GET /%61dmin/announcements (쿠키 없음, 임의 IP)
getRequestURI() 가 디코딩되지 않은 /%61dmin/announcements 를 반환하므로 uri == "/admin" 과 uri.startsWith("/admin/") 이 모두 false 가 되고, shouldNotFilter 가 true 를 리턴해 세션·세션-IP 바인딩·allowlist 검사가 전혀 실행되지 않는다. 이후 DispatcherServlet 은 디코딩된 경로로 AdminAnnouncementController 에 매핑하고, AdminSecurityConfig 의 PathPatternRequestMatcher 도 디코딩 경로로 매칭해 permitAll 체인에 넣는다.
결과는 prod 백오피스의 무인증 읽기·쓰기 접근이다. 공지 브로드캐스트, 등록 한도, 추출 정책이 전부 노출되며 GET 만으로 공격자 세션에 CSRF 토큰이 발급돼 POST 폼도 동작한다.
형제 필터인 EnvironmentAccessFilter 는 이 우회 유형을 /%64ocs/index.html 예시까지 들어 주석에 문서화하고 UrlPathHelper.getPathWithinApplication 으로 막아뒀다. 그 수정이 dev 문서 게이트에만 적용되고 prod 백오피스 게이트에는 적용되지 않았다.
무엇을
AdminAccessFilter.shouldNotFilter 의 경로 판정을 EnvironmentAccessFilter 와 같이 UrlPathHelper 기반으로 바꿔 dispatcher 와 동일한 경로를 보게 한다.
- 우회 표기(percent-encoding, matrix param, 중복 슬래시)가 게이트에 걸리는지 통합 테스트로 고정한다.
왜
AdminAccessFilter.shouldNotFilter가 게이트 적용 여부를 rawrequest.requestURI로 판정하는데, Spring 은 디코딩·정규화된 경로로 라우팅한다. 그래서/admin을 다르게 표기하면 게이트만 건너뛰고 컨트롤러에는 그대로 도달한다.getRequestURI()가 디코딩되지 않은/%61dmin/announcements를 반환하므로uri == "/admin"과uri.startsWith("/admin/")이 모두 false 가 되고,shouldNotFilter가 true 를 리턴해 세션·세션-IP 바인딩·allowlist 검사가 전혀 실행되지 않는다. 이후 DispatcherServlet 은 디코딩된 경로로AdminAnnouncementController에 매핑하고,AdminSecurityConfig의PathPatternRequestMatcher도 디코딩 경로로 매칭해permitAll체인에 넣는다.결과는 prod 백오피스의 무인증 읽기·쓰기 접근이다. 공지 브로드캐스트, 등록 한도, 추출 정책이 전부 노출되며 GET 만으로 공격자 세션에 CSRF 토큰이 발급돼 POST 폼도 동작한다.
형제 필터인
EnvironmentAccessFilter는 이 우회 유형을/%64ocs/index.html예시까지 들어 주석에 문서화하고UrlPathHelper.getPathWithinApplication으로 막아뒀다. 그 수정이 dev 문서 게이트에만 적용되고 prod 백오피스 게이트에는 적용되지 않았다.무엇을
AdminAccessFilter.shouldNotFilter의 경로 판정을EnvironmentAccessFilter와 같이UrlPathHelper기반으로 바꿔 dispatcher 와 동일한 경로를 보게 한다.