이블로그를 포스팅한 계기는 스프링 시큐리티 설정을 Bean 에 주입할때 썻던 코드와 실제 크로스도메인 배포시
생겼던 문제에 대해 궁금증이 생겨 포스팅한글입니닷
Cross-Origin Resource Sharing (CORS)
CORS는 Cross-Origin Resource Sharing의 약자로, 웹 애플리케이션에서 한 출처(origin)에서 불러온 자원을 다른 출처로부터의 요청에 대해 브라우저가 허용하도록 하는 보안 메커니즘입니다.
우리가 흔히 알고 있는 URL 에서 도메인만 뜻하는것이아니라 프로토콜과 포트까지 포함되는 개념입니다.
즉 출처를 구성하는 프로토콜 , 호스트 , 포트 중 하나라도 다르면 CORS 에러를 만나게 됩니다.
즉 Cross - Origin “출처가 교차한다” 라는건 프로토콜 , 호스트 , 포트가 다르다는것이고
CORS를 설정한다는건 출처가 다른 서버간 리소스를 공유를 허용한다는것입니다.
CORS 정책을 보여주기 위한 예시 원본 URL
원본 URL은 "http://example.com"이라고 가정하겠습니다
출처 | URL 접근 가능 여부 | 이유 |
http://example.com/ | 가능 | 원본 URL과 출처 URL이 동일하므로 CORS 정책에 의해 접근 가능 |
https://example.com/ | 불가능 | 프로토콜이 다르므로 Same-Origin 정책에 위배되어 접근 불가능 |
http://subdomain.example.com | 가능 | 서브도메인이 원본 도메인과 같으므로 CORS 정책에 의해 접근 가능 |
http://different.com/ | 불가능 | 출처 도메인이 다르므로 Same-Origin 정책에 위배되어 접근 불가능 |
웹의 발달에 대한 CORS
웹의 발전과 함께 프론트엔드와 백엔드가 분리되고 API 기반의 웹 애플리케이션을 구축하는 것이 일반적으로 되어가고 있습니다.
클라이언트와 서버가 독립적으로 발전할 수 있게 하여 개발 속도와 유지 보수성을 향상시키는데 도움이 됩니다. 그러나 이러한 발전은 동일 출처 정책(Same-Origin Policy)과 관련된 문제가 생기게 됩니다.
이러한 상황에서 CORS(Cross-Origin Resource Sharing)가 등장했습니다. CORS는 서버가 특정 출처에서의 요청을 허용하도록 허용 헤더를 설정하여, 웹 애플리케이션이 다른 출처의 자원에 안전하게 접근할 수 있도록 합니다.
이 사진은 저의 프로젝트중 하나에서 가져온 아키택처입니다.
이부분에서 배포한 백엔드서버의 도메인과 프론트서버의 도메인이 다르게됩니다.
이부분에서 어떻게 CORS를 해결하는지 알아보겠습니다.
CORS 애러 해결방법
1번 . 스프링부트에서 CORS(Cross-Origin Resource Sharing)를 설정하는 방법 중 하나입니다.
서버에서 Access-Control-Allow-Origin 헤더를 설정해서 요청을 수락할 출처를 명시적으로 지정할 수 있습니다.
우선 @Bean 어노테이션을 활용하여 스프링 IOC 컨텍스트에 빈등록을 합니다.
그후 설정은
setAllowedOrigins() | 허용할 출처(origin)를 지정합니다. 이 경우에는 특정 프론트엔드의 URL을 허용하도록 설정되어 있습니다. |
setAllowedMethods() | 허용할 HTTP 메서드를 지정합니다. 주로 GET, POST, PUT, DELETE 등이 허용됩니다. 여기서는 OPTIONS와 PATCH도 허용하도록 설정되어 있습니다. |
setAllowedHeaders() | 요청 헤더 중 허용할 것을 지정합니다. 여기서는 authorization, content-type, x-auth-token을 허용하도록 설정되어 있습니다. |
setAllowCredentials() | 요청 시 자격 증명을 허용할지 여부를 지정합니다. true로 설정되어 있으므로 자격 증명을 허용합니다. |
setExposedHeaders() | 브라우저가 접근할 수 있는 헤더를 지정합니다. 여기서는 x-auth-token을 노출하도록 설정되어 있습니다. |
UrlBasedCorsConfigurationSource | URL 패턴별로 CORS 설정을 관리하는 데 사용됩니다. 여기서는 모든 URL에 대해 같은 CORS 설정을 적용하도록 설정되어 있습니다. |
registerCorsConfiguration() | 특정 URL 패턴에 대한 CORS 설정을 등록합니다. 이 경우에는 "/*" 패턴을 사용하여 모든 URL에 대해 CORS 설정이 적용됩니다. |
그후 스프링 시큐리티를 사용한다면 필터체인에 람다식을 이용해 CORS설정을 주입하면 완료입니다.
2번 .프록시 서버 사용하기
리버스 프록시(Reverse Proxy)는 클라이언트와 서버 사이에 위치하여 클라이언트의 요청을 받고 해당 요청을 다른 서버로 전달하는 서버입니다. 일반적으로 리버스 프록시는 웹 서버로 사용되며, 클라이언트로부터 요청을 받아 백엔드 서버로 전달하여 요청을 처리하고 결과를 클라이언트에 반환합니다. 이를 통해 클라이언트는 백엔드 서버의 존재를 알지 못하며, 리버스 프록시가 클라이언트로부터 요청을 받는 모든 트래픽을 처리합니다.
쉽게말하면 서버와 클라이언트 사이의 중계자 역할을 하는것입니다.
예를 들어, http://example.com라는 주소의 웹 애플리케이션이 http://api.example.com라는 리소스에서 데이터를 요청하는 상황을 가정해 볼게요. 웹 애플리케이션은 직접적으로 리소스에 요청하는 대신, http://example-proxy.com라는 프록시 서버에 요청을 보낼 수 있습니다. 그러면 프록시 서버가 http://api.example.com으로 요청을 전달하고, 응답을 다시 웹 애플리케이션에 반환하는 거죠. 이렇게 하면 요청이 http://example-proxy.com보내진 것처럼 보이므로, CORS 에러를 피할 수 있습니다.
CSRF 는 또 뭘까요?
CSRF 공격은 공격자가 사용자의 신원을 도용하여 사용자가 인증된 상태로 서버에 요청을 보내는 공격입니다.
예를 들어, 악의적인 공격자가 사용자의 계정에서 자금 이체를 실행하는 요청을 보내는 웹 페이지를 만들고, 이 페이지에 사용자를 유도하는 링크를 만듭니다. 사용자가 이 링크를 클릭하면, 자동으로 해당 웹 페이지가 열리고 사용자의 인증된 세션을 사용하여 자금 이체 요청이 서버에 전송됩니다. 이때 사용자는 이 공격을 식별할 수 없으며, 자금이 이체되었다는 사실을 알지 못할 수 있습니다.
난 왜 프로젝트에서 CSRF를 disable 했을까?
그것은 바로 JWT 토큰인증 방식을 썻기 때문입니다.
서버로부터 발급된 토큰을 클라이언트에게 전달하고 , 클라이언트는 이를 보유하여
서버에 요청을 보낼때마다 함께 보내게 됩니다.
따라서 CSRF는 세션 정보를 탈취해서 사용자인척하여 악의적인 행위를 하는데
JWT는 세션 쿠키가 아니므로 이러한 공격에 노출되지 않습니다. 때문에 CSRF를 비활성화하여 추가적인 오버헤드를 줄일 수 있습니다.
느낀점
이번 글을 통해 CORS와 CSRF에 대한 이해를 높일 수 있었습니다. CORS는 웹 애플리케이션에서 다른 출처의 자원을 안전하게 요청하고 응답받을 수 있도록 해주는 메커니즘이며, 이를 설정함으로써 웹 애플리케이션의 보안성을 높일 수 있습니다. 또한, 리버스 프록시를 사용하여 CORS 문제를 해결할 수도 있습니다.
또한, CSRF 공격은 사용자의 인증된 세션을 도용하여 악의적인 요청을 보내는 공격으로, 이를 방어하기 위해 CSRF 토큰을 사용하거나, JWT와 같은 토큰 기반의 인증 방식을 사용할 수 있습니다. 이를 통해 웹 애플리케이션의 보안성을 높일 수 있습니다.
마지막으로, 프로젝트에서 CSRF를 비활성화한 이유는 JWT를 사용하고 있기 때문입니다. JWT를 사용하면 세션 쿠키가 아니므로 CSRF 공격에 취약하지 않으며, 추가적인 오버헤드를 줄일 수 있습니다.
이를 통해 보다 안전하고 효율적인 웹 애플리케이션을 개발할 수 있을 것입니다.
'컴퓨팅사고' 카테고리의 다른 글
SOLID 의 개념과 스프링 부트 예시😁 ( OOP ) ⊙.☉ (0) | 2024.04.03 |
---|---|
정규표현식을 알아보고 검증해보기:(RegExp) 이해 (0) | 2024.03.23 |
s/w problem solving (1) (0) | 2023.07.04 |