스프링부트 프로젝트 개발을 하며
Spring Security와 더불어, 개발과정에서 h2 데이터베이스에서 제공하는 In-Memory 기능을 이용하기로 하였다.
h2 데이터베이스와 스프링 시큐리티를 같이 이용하려면
특별히 몇 개의 설정을 더 해주어야 한다.
바로 다음과 Security Filter Chain을 등록해서
CSRF 보호 비활성화, X-Frame-Options 헤더를 SAMEORIGIN으로 설정하는 것이다.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
...
.csrf(AbstractHttpConfigurer::disable)
.headers(headers -> headers
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin))
...
return http.build();
}
원래는 위와 같이 설정을 해 주어야 동작을 하지만,
나는 csrf 보호 비활성화만 지정을 해놓고,
X-Frame-Options와 관련된 헤더 설정을 하지 않은 채
h2콘솔에 접속하니 다음 화면이 나왔다.
# localhost:8080/h2-console 접속 후 로그인
단 하나의 설정을 빠트린 대가가 이렇게나 크단 말인가.
대체 왜 이런 오류가 나왔는 지 알기 위해서
여러 자료를 찾아가며 공부를 하였다.
iframe 태그
먼저 X-Frame-Options 헤더가 무엇인가를 공부하기 전에,
<iframe>이라는 태그를 통해 다른 웹 페이지를 컨텐츠로 표시할 수 있는 기능에 대하여 공부를 하여야 효과적이다.
다음과 같이, 현재의 웹 페이지 내에 다른 페이지의 컨텐츠를 표시할 수 있는 기능이 있다.
<iframe src="https://example.com" width="600" height="400"></iframe>
그러니까, 이 iframe 헤더를 이용하면 가로 600픽셀 세로 400픽셀의 크기로
"https://example.com"으로 접속했을 때 나오는 컨텐츠를
현재 웹 페이지상에 표시를 할 수가 있다.
흔히들 맛집 찾으러 다닐 때 맛집 정보가 나오고
그 다음에 구글맵같은걸 이용해서 화면에 지도가 표시될 때
이런 기능이 이용된다고 한다.
아마도 다음과 같이 구현되어 있을 것이다.
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3151.835434509805!2d144.95373531531915!3d-37.81627997975184!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x6ad642af0f11c5e3%3A0x5045675218cee20!2sMelbourne%20CBD!5e0!3m2!1sen!2sau!4v1615960720531!5m2!1sen!2sau" width="600" height="450"></iframe>
ClickJacking 공격
우리는 iframe헤더를 이용해서,
내 웹 페이지 내에 다른 웹 페이지를 얼마든지 로드해서 사용할 수 있다는 것을 알게 되었다.
하지만 이게 꼭 좋은 것인지는 생각을 해 봐야 한다.
누군가는 다음과 같은 걱정을 할 수도 있다.
"누군가가 내 웹 컨텐츠를 함부로 가져다가 자신의 웹 페이지에 표시되도록 하면 어떡하지?"
실제로 해커가 만든 웹 페이지에서,
iframe을 통해 금융 거래 웹 사이트의 페이지를 불러와서 보이지 않게 숨기고,
버튼을 클릭하면, 금융거래 웹 사이트의 특정 버튼이 눌려져서 돈을 이체하도록 하는 공격을 할 수도 있다.
이런 공격을 클릭재킹 공격(ClickJacking)이라고 한다.
X-Frame-Options헤더
이러한 클릭재킹 공격이 일어나지 않도록 하기 위해서 어떻게 해야 할까?
답은 간단하다.
"나를 다른 곳에서 함부로 사용하지 못하도록"하면 된다.
위 은행 사이트 예시의 경우에는, "내 웹 사이트를 함부로 다른 도메인에서 iframe으로 불러오지 못하도록"하면 되는 것이다.
이 때 사용하는 것이 바로 X-Frame-Options헤더이다.
X-Frame-Options를 SAMEORIGIN으로 설정한다면,
오로지 동일한 도메인 내에서만 해당 페이지를 iframe으로 불러올 수가 있다.
스프링 시큐리티에서는 이 X-Frame-Options를 지정하지 않으면 디폴트로 Deny가 설정되어,
그 어떠한 경우에도, 어디서도 해당 페이지를 iframe으로 불러올 수 없게 된다.
H2-console에서 문제의 화면
문제의 화면을 다시 자세히 살펴보자.
개발자 도구를 이용해 살펴보면, h2-console화면은
frame이라는 태그를 통해 다른 자원을 표시하도록 구현이 되어 있다.
<frame noresize="noresize" frameborder="0" marginheight="0" marginwidth="0" src="header.jsp?jsessionid=0340fe8bf5d09068c343660456ea676e" name="header" scrolling="no">
그리고 맨 밑에를 보면, X-Frame-Options가 DENY로 설정이 되어 있어서 diaplay하지 못했다는 오류가 있다.
그렇다.
스프링 시큐리티에서 별도의 설정이 없을 경우에는 X-Frame-Options를 설정하지 않았으니
이 헤더의 값은 DENY로 자동설정이 되며,
이렇게 되면 해당 모든 도메인 내의 웹 페이지는 그 어디서도 <frame> 혹은 <iframe>태그로 로드될 수가 없게 되는 것이다.
그런데 위 frame에서는 어느 경로를 불러와서 컨텐츠로 표시하려고 하고 있는가?
바로 다음 부분이다.
http://localhost:8080/h2-console/header.jsp?jsessionid=0340fe8bf5d09068c343660456ea676e
http://localhost:8080이라는 도메인의 위 페이지를 로드하려는 순간 다음과 같은 순서로 전개된다.
1. HTTP 요청을 보냄
2. HTTP 응답을 받는다. 그리고 그 헤더를 확인해 보니, X-Frame-Options값이 DENY이다.
3. 브라우저가 이를 표시하기를 거부한다.
그래서 위와 같이 웹 페이지를 표시할 수 없다는 아이콘이 나왔던 것이다.
이처럼 브라우저 단에서도 각종 보안과 사용자의 안전을 위해 여러 안전 장치가 마련이 되어 있다.
끝을 맺으며
Spring security가 6 이상 버전으로 올라가며
코딩스타일이 Lambda DSL로 바뀌고,
이 최신 스타일의 코드를 얻는 것이 쉽지 않다.. 그래서 아주 사소해 보이는 설정 하나를 생략했던 것인데
이 설정 하나를 생략해서 결과적으로는 큰 오류를 범하게 되었던 것이다.
덕분에 많은 공부를 하게 되었으니. 후회는 없다
'Web Security' 카테고리의 다른 글
[2] HTTPS 프로토콜 쉽게 이해하기 - 인증서의 개념 (0) | 2024.05.02 |
---|---|
[1] HTTPS 프로토콜 쉽게 이해하기 - 대칭 키와 비대칭 키 (0) | 2024.05.01 |
[APMSetup] php.ini를 수정하여 사용자의 입력값을 자동으로 escape하기 (0) | 2022.03.05 |