티스토리 뷰

항해99

[항해 99] 5 WIL [CORS]

오두기밥 2022. 6. 12. 23:29

INTRO

항해 99 5번째 주차 스프링 숙련 주차가 끝났다. 기존에 배운 것들로 간단한 주문 프로그램을 구현하는 주차였다. 

이번 주문 프로그램을 구현 하면서, JPA를 사용한 엔티티 연관관계를 표현하는 OneToMany, ManyToOne, ManyToMany, OneToOne을 사용해 각각의 테이블을 설계하면서, 필요한 테이블과의 연관관계를 통해 기존에 id 값만 저장해서 조회하는 것이 아닌, 관계를 통해 조회하는 방식을 사용해 보면서 공부할 수 있는 시간이었다.

 

이전에도 JPA를 사용하면서 연관 관계 어노테이션을 사용했고, 각 어노테이션의 fetch 타입을 사용해봤었지만, 스프링 부트에서의 사용은 처음이었다. 그래서 lazy와 eager가 정확하게 동작하는지, 확인을 해보았지만 controller에서도, service에서도  lazy로 설정해둔 칼럼을 조회해도, eager로 설정해보아도, lazy exception이 발생하지 않아서, 이게 왜? 이럴까라는 의문을 가졌다.

그리고 공부를 하다 보니 Spring boot JPA의존 관계를 주입받아  사용하면 기본적으로 osiv 설정이 true 인 것을 알게 되었고 osiv에 대해 살짝 공부할 수 있었던 시간이었다. 이 부분은 또 따로 포스팅을 해보도록 해야겠다.

 

그리고 연관 관계 테이블에 대해 공부하다가 N+1의 문제라는 것을 알게 되었다, OneToMany 칼럼을 조회할 때 해당 엔티티를 조회하면 연관된 테이블의 select가 n 번 발생하는 문제라는 것을 알았고, 이를 해결하는 방법이 fetch join을 통해 조회를 하는 것이었다. 하지만, @Query를 통해 fetch join을 사용하면, pageable을 사용할 수 없었고, 이에 대한 해결책으로 

querydsl을 사용한 fetch join을 공부할 수 있었고, 조금 더 공부해보고 포스팅을 해보도록 해야겠다. 

 

그리고, 이어진 주차는 처음으로 프런트 개발자 분들과 협업을 해볼 수 있었다. 서로 다른 특징을 가진 언어로 의사소통을 하는 것이 쉽지는 않았지만, 내가 알고 있는 것을 프론트 분들에게 설명하면서, 내가 알고 있는 것을 정리할 수 있는 좋은 시간이었다. 특히, react와 스프링 서버로 구성해서 같이 사용하면, cors라는 것을 공부할 필요가 있었고, 하단에 정리를 해보았다. 

 


 

CORS(Cross-Origin Resource Sharing)

  • 브라우저에서 다른 출처의 리소스를 공유하는 방법 

 

1) 출처란(ORIGIN)

  • URL 구조에서 살펴본 Protocol, Host, Port를 합친 것을 말한다.

2) CORS 동작원리

기본적으로 웹 클라이언트 애플리케이션이 다른 출처의 리소스를 요청할 때는 HTTP 프로토콜을 사용하여 요청을 보내게 되는데, 이때 브라우저는 요청 헤더에 Origin이라는 필드에 요청을 보내는 출처를 함께 담아 보낸다.
Origin: https://tistory.com
이후 서버가 이 요청에 대한 응답을 할 때 응답 헤더의 Access-Control-Allow-Origin이라는 값에 “이 리소스를 접근하는 것이 허용된 출처”를 내려주고, 이후 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과 서버가 보내준 응답의 Access-Control-Allow-Origin을 비교해본 후 이 응답이 유효한 응답인지 아닌지를 결정한다.

 

Simple Request

단순 요청은 서버에 API를 요청하고, 서버는 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. 브라우저는 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다.

 

Simple Request 조건

아무 때나 단순 요청을 사용할 수 있는 것은 아니고, 특정 조건을 만족하는 경우에만 예비 요청을 생략할 수 있다. 게다가 이 조건이 조금 까다롭기 때문에 일반적인 방법으로 웹 애플리케이션 아키텍처를 설계하게 되면 거의 충족시키기 어려운 조건들이다.

  • 요청의 메서드는 GET, HEAD, POST 중 하나여야 한다.
  • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안 된다.
  • 만약 Content-Type를 사용하는 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용된다.

사실 1번 조건의 경우는 그냥 PUT이나 DELETE 같은 메서드를 사용하지 않으면 되는 것뿐이니 그렇게 보기 드문 상황은 아니지만, 2번이나 3번 조건 같은 경우는 조금 까다롭다.

애초에 조건에 명시된 헤더들은 정말 기본적인 헤더들이기 때문에, 복잡한 상용 웹 애플리케이션에서 이 헤더들 외에 추가적인 헤더를 사용하지 않는 경우는 거의 없고, 당장 사용자 인증에 사용되는 Authorization 헤더조차 조건에는 포함되지 않는다.

3번 조건은 많은 REST API들이 Content-Type으로 application/json을 사용하기 때문에 지켜지기 어려운 조건이다.

 

Preflight request

프리플라이트(Preflight) 방식은 서버에 예비 요청을 보내서 안전한지 판단한 후 본 요청을 보내는 방법이다. 브라우저는 요청을 한 번에 보내지 않고 예비 요청과 본 요청으로 나누어서 서버로 전송한다.

이때 브라우저가 본 요청을 보내기 전에 보내는 예비 요청을 Preflight라고 부르는 것이며, 이 예비 요청에는 HTTP 메서드 중 OPTIONS 메서드가 사용된다. 예비 요청의 역할은 본 요청을 보내기 전에 브라우저 스스로 이 요청을 보내는 것이 안전한지 확인하는 것이다.

우리가 자바스크립트의 fetch API를 사용하여 브라우저에게 리소스를 받아오라는 명령을 내리면 브라우저는 서버에게 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 현재 자신이 어떤 것들을 허용하고, 어떤 것들을 금지하고 있는지에 대한 정보를 응답 헤더에 담아서 브라우저에게 다시 보내주게 된다.

이후 브라우저는 자신이 보낸 예비 요청과 서버가 응답에 담아준 허용 정책을 비교한 후, 이 요청을 보내는 것이 안전하다고 판단되면 같은 엔드포인트로 다시 본 요청을 보내게 된다. 이후 서버가 이 본 요청에 대한 응답을 하면 브라우저는 최종적으로 이 응답 데이터를 자바스크립트에게 넘겨준다.

 

Credentialed Request

3번째 시나리오는 인증된 요청을 사용하는 방법이다. 이 시나리오는 CORS의 기본적인 방식이라기보다는 다른 출처 간 통신에서 좀 더 보안을 강화하고 싶을 때 사용하는 방법이다.

기본적으로 브라우저가 제공하는 비동기 리소스 요청 API인 XMLHttpRequest 객체나 fetch API는 별도의 옵션 없이 브라우저의 쿠키 정보나 인증과 관련된 헤더를 함부로 요청에 담지 않는다. 이때 요청에 인증과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션이다.

이 옵션에는 총 3가지의 값을 사용할 수 있으며, 각 값들이 가지는 의미는 다음과 같다.

옵션 값 설명

same-origin (기본값) 같은 출처 간 요청에만 인증 정보를 담을 수 있다
include 모든 요청에 인증 정보를 담을 수 있다
omit 모든 요청에 인증 정보를 담지 않는다

same-origin 은 기본 값으로, 같은 출처 간에 쿠키 등의 인증 정보 전달이 가능하다. include는 출처에 상관없이 모든 요청에 쿠키 등의 인증 정보를 전달할 수 있다. omit 은 쿠키 등의 인증 정보를 전달하지 않는다.

만약 same-origin이나 include와 같은 옵션을 사용하여 리소스 요청에 인증 정보가 포함된다면, 이제 브라우저는 다른 출처의 리소스를 요청할 때 단순히 Access-Control-Allow-Origin 만 확인하는 것이 아니라 좀 더 빡빡한 검사 조건을 추가하게 된다.


 

마무리

단순한 주문 프로그램 구현을 해보았지만, 영속성 콘텍스트, 쓰기 지연 저장소, transaction의 기본적인 동작 원리, AOP 사용법을 공부하고 적용해 볼 수 있는 좋은 시간이었다. 정말 스프링은 공부하면, 할 수 록 해야 하는 공부가 많은 것 같지만, 확실히 공부한 만큼 더 좋은 방법에 접근할 수 있는 능력이 늘 수 있다는 것을 다시 한번 알 수 있었다.  

 

 

참고

 

CORS(Cross-Origin-Resource Sharing) 란?

CORS 란? CORS는 Cross-Origin Resource Sharing의 약자이다. 브라우저에서 다른 출처의 리소스를 공유하는 방법이다. 아래의 CORS policy 오류 메시지는 CORS 정책을 위반할 때 발생한다. URL 구조 출처를 알기

velog.io

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함