Java Spring - SPA, CORS

김재현·2022년 8월 4일
0

Programmers

목록 보기
12/28
  • REST API를 이용해 만드는 단일페이지 웹 어플리케이션
  • REACT라는 자바 스크립트 어플리케이션과 연동
  • CORS에러에 대해서 알아보자.

단일 페이지 웹 어플리케이션 (Single-Page Application)

단일 페이지 웹 어플리케이션

  • JSP, 타임리프와 다르게 화면에서 그려지는 내용을 서버에서 처리하지 않고, 브라우저에서 처리. 다이나믹한 랜더링을 브라우저에서 처리.

전통적인 방법(위에 그림)

브라우저에서 request > 서버에 전송 > HTML을 브라우저에 전달 > 화면의 URL 변경 > 랜더링 됨 > 이후 모든 작업에 이를 반복.
POST를 써도 서버가 redirect하면서 화면이 변경됨.
매번 페이지에 리로딩된다.

단일 페이지 어플리케이션

브라우저에서 request > 서버에 전송 > HTML을 브라우저에 전달 > 화면의 URL 변경 > 랜더링 됨 > 로드가 한 번 완료되면 이 작업을 반복하지는 않음.
로드가 한 번 완료되면, 클라이언트가 AJAX는 기술을 이용해서 URL이 변경되지 않고, 백단에서 대체로 HTTP요청을 보냄. 서버가 응답을 받아서 JSON응답을 주고 클라이언트는 그것으로 메모리를 읽고 그 데이터로 화면을 랜더링 함.

  • 일반 웹 애플리케이션의 경우 화면 전체가 랜더링된다. 실제 작업이 수행되는 부분 외(상단 부분, 좌측 메뉴 등등)의 부분도 랜더링되고 관련된 자바 스크립트를 다시 읽는다.
    레이아웃도 서버에서 처리.
  • 단일 페이지 웹 애플리케이션은 URL변경 시 특정 영역만 랜더링되게 할 수 있음. DOM의 조작을 통하여 랜더링이 이루어지게 된다.

전통적인 방식

  • 요청들은 스테이스리스하다 = 요청들끼리 공유된 데이터가 없다. HTTP요청 자체는 상태가 없다.
  • 세션은 대체로 로그인을 하면 만들어짐. 사용자가 웹 서비스에 접근해서 머문 일정 시간동안 유지된 상태를 세션이라고 생각하면 된다.
    처음 로그인하면 사용자에 대한 세션을 생성. 로그인 시 사용자 정보가 세션에 보관됨. 사용자 요청이란 것을 알기 위해서 세션 아이디를 매 요청마다 쿠키에 실어서 보냄. 세션 아이디를 가지고 세션을 찾아, 세션이 유지되는 동안 한 사용자의 요청이라는 것을 서버가 알 수 있음.
  • 세션은 서버에서 관리.
    사용자 세션이 서버에 만들어지고, 첫 로그인에 쿠키가 생성. 이후 요청이 들어오면 사용자 정보가 쿠키게 담겨 전달됨. 쿠키에 있는 세션 데이터를 갖고 사용자 데이터 모델을 찾고 사용자 ID 등을 세션에서 호출.

SPA 기반

  • 세션에 사용자 ID등 말고도 메뉴 정보 같은 것들이 들어갈수도 있고, 그 경우 세션이 계속 커진다.
  • 사용자데이터 모델의 일부를 브라우저에서 관리하게 함. 브라우저에서 메모리로 들게 한다.
    브라우저의 Local Storage라는 기능을 이용. 브라우저도 매 요청에 웹페이지 전체를 로드하는 것은 아니다.
    요청을 할 때마다 정보들이 브라우저의 저장소에 담겨 있기 때문에 세션까지 가지 않더라도 처리할 수 있다.
  • 매번 전체 화면을 변경하는 것이 아니고 변경이 필요한 부분만 DOM을 이용해 변경한다.

Same-Origin Policy

참고

  • 하나의 웹 애플리케이션이 하나의 호스트에서 데이터를 가져올 필요는 없다.
    웹 애플리케이션은 갈수록 복잡해지고 다양한 컨텐츠를 보여줘야하기 때문에 다양한 리소스가 필요하고, 다양한 호스트에 접근해 데이터를 갖고와야 함.
  • 다양한 호스트에 접근해야 됨 > 보안이 중요해진다.
    사용자를 악의적인 행위에서 보호하기 위해 브라우저는 Same Origin(동일출처)에서만 리소스 접근을 허용할 수 있게하는 Same-Origin Policy를 만들게 되고, 동일 출처의 리소스에 접근을 할 수 있음.
  • 어떤 출처에서 불러온 리소스가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 보안 정책. 스크립트에만 적용되며, 동일한 출처의 웹페이지일때만 리소스에 접근하는 것을 허용.
  • 웹 애플리케이션은 동일한 출처에만 접근이 가능.

  • URL의 host, protocol, port가 동일하면 same origin이라고 부름.
    http는 프로토콜, store.company.com가 호스트, :80이 포트.
    포트는 기본값이 있기 때문에 생략되는 일이 많은듯하다.
  • 어떤 페이지의 악의적인 스크립트가 다른 페이지의 DOM을 통해 데이터에 접근하는 것을 방지한다.
  • 이미지, CSS 같은 리소스는 HTML 태그를 통해 다른 출처여도 접근할 수 있다.

⚠️ 사용자를 보호하기 위한 클라이언트 측 정책으로 요청이 들어오면 서버에서는 다른 출처여도 정상적으로 응답하지만 브라우저 단에서 SOP를 확인해 처리한다. 따라서 서버 간 통신에는 적용되지 않는다 ⚠️

CORS (Cross-Origin Resource Sharing)

가이드

  • CORS는 HTTP-header 기반 방식으로 서버가 브라우저에서 리소스 로딩을 할 수 있는 다른 출처를 허용할 수 있게 하는 메커니즘을 말한다.
  • 애플리케이션은 다양한 출처의 데이터에 접근해야하고 다른 출처 간 리소스 사용을 무조건 막을 수 없기에, 제한된 설정을 통해 부합하는 출처에서 통신을 허용한다.
  • 작동방식
    1) 클라이언트가 다른 출처의 리소스를 요청할 때 헤더에 Origin 필드에 요청을 보내는 출처를 함께 보낸다.
    2) 이후 서버가 응답할 때 응답 헤더의 Access-Control-Allow-Origin 필드에 해당 리소스에 접근이 허용된 출처를 보낸다.
    3) 응답을 받은 클라이언트는 보냈던 요청의 Origin과 응답의 Access-Control-Allow-Origin을 비교해 유효한 응답인지를 결정한다.
  • CORS의 세세한 동작 방식은 Preflight, Simple, Credentialed 3가지 시나리오에 따라 조금씩 다르다.

⚠️ 사용자를 보호하기 위한 클라이언트 측 정책으로 요청이 들어오면 서버에서는 다른 출처여도 정상적으로 응답하지만 브라우저 단에서 CORS를 확인해 처리한다. 따라서 서버 간 통신에는 적용되지 않는다 ⚠️

예비요청(PreFlight Requests)

  • CORS는 PreFlight(예비 요청) 요청이 있고 없고에 따라서 flow가 좀 다르다.
    단순요청이 아닐 때는 예비 요청을 보냄.
  • 브라우저가 요청을 한번에 보내지 않고 예비 요청과 본 요청으로 나눠 서버로 전송한다. 이때 예비요청을 preflight이라 부른다.
  • 예비 요청은 OPTIONS이라는 HTTP 메서드로 보내게 되며 OPTIONS에 Origin을 실어서 보내게 됨.
Acces-Control-Allow-Origin: *
  • 위 헤더로 서버가 엑세스를 허용하는 오리진에 대한 정보를 보내게 되는데, URL을 보낼 수도 있다. *를 보내면 이 서버는 모든 호스트로부터 CORS를 허용하는 것을 인지하고 다음 본 요청을 보내게 되며 그 후 본 요청을 처리.

단순요청(Simple Requests)

  • 예비요청 없이 바로 본 요청을 보내고, 응답에 따라 CORS 정책 위반 여부를 검사한다.
  • 단, 다음 요청을 모두 충족하는 요청이어야 simple requests
    1) 메서드 사용
    GET HEAD POST
    2) 다음의 헤더를 사용
    Accept Accept-Language Content-Language Content-type DPR Downlink Save-Data Viewport-Width Width 이외의 헤더를 사용하면 안됨.
    3) Content-Type 헤더는 다음의 값들만 허용. 이 외의 값을 사용하면 단순요청이 아님.
    application/x-www-form-unlencoded multipart/form-data text/plain

(Credentialed Request)

  • 다른 출처 간 통신의 보안을 강화하고 싶을 때 사용.
  • 비동기 리소스 요청은 쿠키나 인증 관련 헤더를 별도 옵션 없이 헤더에 담지 않는다. 요청에 인증 관련 정보를 담게 해주는 옵션이 credentials이다.

  • include의 경우 다음 조건이 충족돼야한다
    1) Access-Control-Allow-Origin에 * 사용 X, URL 명시
    2) 응답 헤더에 Access-Control-Allow-Credentials: true 존재

  • 서버가 Access-Control-Allow-Origin: *을 주지 않으면 본 요청이 실패함.

## Auto configuration

  • configuration를 통해서 앱을 구성할 수 있도록 도와줌.

0개의 댓글