CORS 원인과 해결하기

송수용·2022년 6월 17일
0

백엔드의 기술

목록 보기
9/11

CORS란?

교차 출처 리소스 공유(Cross-origin resource sharing, CORS), 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다.

SOP란

CORS 에러는 SOP라는 브라우저의 원칙으로 인해 발생한다.
SOP는 Same Origin Policy로, 동일 출처가 아닌 경우 발생한다.
여기서 동일 출처는 프로토콜,호스트,포트가 동일한 경우이다.

SOP가 필요한 이유

동일 출처가 아닐 경우 브라우저가 접근을 차단하는 이유는 무엇일까?

사용자가 웹사이트에 접근할 때는 브라우저의 쿠키에 로그인 세션 토큰을 남기게된다.
해당 토큰을 사용해 사용자는 매번 로그인할 필요없이 서비스를 이용할 수 있다.
웹사이트는 토큰을 받아 파싱 및 해석하여 로그인되었음을 확인한다.

하지만 로그인 토큰이 남아있는 브라우저에서 사용자가 악성 사이트에 접속한 경우,
악성 사이트는 사용자 브라우저의 토큰에 접근할 수 있다.
악성 사이트가 해당 토큰으로 다른 웹 사이트에 로그인할 경우, 사용자는 해킹에 노출된다.

이 상황에 브라우저는 SOP에 따라 이러한 상황을 막아준다.
브라우저는 악성 사이트의 요청서버와 응답을 주는 응답 서버의 출처가 다른 것을 보고
CORS 에러를 뱉는다.

웹 사이트 서버에서 악성사이트를 허가해주지 않는 이상, 악성사이트는 CORS에러로 정상적으로 로그인할 수 없기때문이다.

SOP로 발생하는 에러를 해결하는 방법

SOP로 사용자를 보호할 수 있지만, 서버는 점차 확장되고 가끔은 다른 회사의 서버부를 이용해야(API 사용 등) 하는 상황이 자주 발생한다.
따라서 조건에 맞게 이런 다른 출처들을 허가해주어야 한다.

  1. 단순 요청 Simple
    요청만으로 서버에 영향을 주지 않는 단순 요청의 경우,

  2. 서버에게 본 요청을 전달한다.

  3. 서버가 OK와 Access-Control-Allow-Origin를 보낸 경우 응답을 전달한다.

  4. Access-Control-Allow-Origin이 안오면 본요청이 fail되고 브라우저는 CORS에러를 발생시킨다.

  5. 예비요청이 있는 경우 Preflight
    단순요청이 아닌경우, 예비요청을 통해 허가를 받은 후, 본 요청을 할 수 있습니다.

  6. OPTIONS 메소드로 Origin(호스트 uri)을 실어서 보낸다. (예비 요청)

  7. 서버가 요청을 허가할 경우 OK랑 Access-Control-Allow-Origin을 보낸다.

  8. 브라우저는 서버의 허가를 확인 후 본 요청을 보내게 된다.

CORS의 해결방법

  1. 프론트엔드에서 프록시 이용
    우선 cors에러는 브라우저를 통과하며 발생합니다.
    따라서 온전한 서버끼리의 통신에서는 발생하지 않습니다.
    프론트엔드 단의 웹서버에서 요청을 프록시 형태로 감싸 백엔드 서버로 바로 요청할 경우, 에러가 발생하지 않습니다.

  2. 백엔드 서버에서 허가
    백엔드 서버에서 Access-Control-Allow-Origin 응답을 설정하게 하여, 임의로 허가를 내려줄 수 있습니다.

스프링 서버 전역적으로 CORS 설정

static class AppConfig implements WebMvcConfigurer {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/api/**")
                    .allowedMethods("GET", "POST") //메소드 지정 가능
                    .allowedOrigins("*"); //와일드 카드: 전체 다 허락
        }
    }   

특정 컨트롤러나 메소드에 개별적 CORS 설정
@Controller

@CrossOrigin(origins = "*", methods = RequestMethod.GET) 
public class customController {
   
    @GetMapping("/url")  
    //특정 메소드에만 CORS 적용 가능
    @CrossOrigin(origins = "*", methods = RequestMethod.GET) 
    @ResponseBody
    public List< > findAll(){
        return service.getAll();
    }

}
  1. Chrome 확장 프로그램 이용

https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf

  1. 서버에서 Access-Control-Allow-Origin 세팅하기

서버에서 해결하기
스프링 CORS
@CrossOrigin 어노테이션 사용하기
메소드 레벨 및 글로벌 레벨에서 srping mvc 애플리케이션에서 spring cors를 지원하는 방법이다. sprign mvc는 @CorssOrigin 어노테이션을 제공한다. 이 어노테이션은 어노테이션이 달린 메소드 또는 타입을 교차 출처를 허용하는 것으로 표시한다.

기본적으로 @CrossOrigin은 모든 출처, 모든 헤더, @RequestMapping 주석에 지정된 Http 메소드에 최대 30분을 허용한다. 어노테이션에 속성 값을 넣어 기본 값을 대체할 수 있다.

속성값을 살펴보면,

origins
허용된 출처, 이 값은 pre-flight 응답과 실제 응답 모두에 access-control-allow-origin헤더에 배치된다.
allowedHeaders
실제 요청 중에 사용할 수 있는 요청 헤더 목록이다. pre-flight의 응답 헤더인 access-control-allow-header에 값이 사용된다.
allowCredential
브라우저가 요청과 관련된 쿠키를 포함해야 되는지 여부를 결정한다.
이 값이 true이면, pre-flight 응답에는 값이 true로 설정된 access-control-allow-credentials 헤더가 포함된다.

@CrossOrigin(origin="*", allowedHeaders = "*")
@Controller
public class MainController {
	@GetMapping(path = "/")
	public String main(Model model) {
		return "main";
	}
}

profile
#공부중 #협업 #소통중시 #백엔드개발자 #능동적 #워커홀릭 #스파르타코딩 #항해99 #미니튜터 #Nudge #ENTJ #브레인스토밍 #아이디어뱅크

0개의 댓글