회사에서 프로젝트를 진행하는 중에, 유저의 설정에 따라 css가 다르게 적용되어야 했다.
css의 템플릿은 정해져있었고, 색상 코드 / 정렬 / image URL 등을 커스터마이징 해서 사용하는 기능이다.
custom css는 팝업 창에 필요하므로, 팝업창을 열 때 css 의 URL을 파라미터로 전달하고, 팝업창에서는 전달받은 css를 link 태그의 href로 설정한다.
이 중에 후자의 방법을 채택하였는데, 이유는
물론 단점도 존재했는데,
위와 같이 해결을 했다.
물론, 요청이 많아져서 서버에 부하가 생길 경우를 대비하여 전자의 방안으로 확장성도 고려했다.
chrome 브라우저에서 API 호출하면, 응답이 되지 않았다.
API를 호출 하고, 200 응답을 받았는데도
응답값이 없었다.
교차 출처 읽기 차단(CORB)으로 MIME 유형이 text/plain인 교차 출처 응답(...)이 차단되었습니다.
CORB(Cross-Origin Read Blocking)는 Cross-Origin Resource 공격을 방지하기 위한 클라이언트
의 보안 기능이다.
리소스 요청 시 동일 출처 정책(Same-Origin Policy)에 위배되는 상황에서 발생할 수 있다.
(*동일 출처 정책 : A사이트에서는 A사이트에 존재하는 리소스를 사용해야 한다.
즉, A사이트에서 B사이트의 리소스를 요청하는 등, 요청과 응답의 서버가 다르면 안된다.)
Cross-Origin Resource 요청
브라우저에서 스크립트 또는 AJAX 요청을 통해 다른 도메인의 리소스 (예: 이미지, 스크립트, CSS 파일)를 가져오려고 할 때 발생할 수 있다. (동일 출처 정책 위배)
잘못된 응답 유형
서버에서 보내는 응답 헤더 중, X-Content-Type-Options: nosniff
가 설정되어 있고, 다른 도메인에서 반환된 응답이 잘못된 유형일 경우 CORB 오류가 발생할 수 있다.
예를 들어, <img src = "http://example.com/sample.json">
과 같이 img 태그의 리소스에 image 형식의 응답이 아닌 경우에 발생할 수 있다.
JSONP 사용
JSONP(JSON with Padding)는 json 형태의 데이터에 대해서, Cross-Origin 요청을 허용하기 위한 대안적인 방법이다.
JSONP는 스크립트 태그를 사용하여 다른 도메인에서 데이터를 동적으로 로드하는 방식이다.
프록시 서버 설정
클라이언트는 프록시 서버에 요청을 보내고, 프록시 서버는 원격 서버로부터 데이터를 가져와 클라이언트에게 전달하여 동일 출처 정책 위배를 우회할 수 있다.
리소스의 도메인 변경
클라이언트와 리소스 서버를 관리하는 주체가 동일하고, 둘의 origin이 다르다면
리소스 서버의 도메인을 클라이언트와 동일하도록 변경하여 동일 출처 정책을 만족시킬 수 있다.
리소스 유형 변경
CORB 오류가 발생하는 리소스의 유형을 변경할 수도 있다. 서버 측 Content-Type 응답 헤더를 수정한다.
CORS 허용 범위 확장
서버의 응답 헤더를 Access-Control-Allow-Origin: *
로 설정하여 모든 도메인에서의 요청을 허용할 수 있다. (이 방법은 보안 상의 위험이 있으므로 신중하게 사용해야 한다)
Cross-Origin 리소스 공유 허용
서버의 응답 헤더를 Access-Control-Allow-Credentials: true
로 설정하여 자격증명이 필요한 요청에 대해 Cross-Origin 리소스 공유를 허용할 수 있다.
단, 이 경우 CSRF (Cross-site request forgery, 사이트 간 요청 위조) 공격에 매우 취약해져, Access-Control-Allow-Origin: *
와 함께 사용할 수 없다.
브라우저 확장 프로그램 사용
브라우저의 확장 프로그램을 사용하여, 브라우저의 동작을 수정하고 Cross-Origin 제약을 해제하여 CORB 오류를 해결한다.
위에 CORB 오류가 발생하는 상황 2가지에 대해 소개했다.
우선 [위 사진](#이슈 내용) 에서 우리 API의 응답 헤더가 어떻게 내려오는지 한번 살펴보고 오면 좋다.
Cross-Origin Resource 요청
우리는 API를 제공하고 있기 때문에 Access-Control-Allow-Origin: *
헤더가 설정되어있다. 따라서, CORS 이슈는 발생하지 않는다.
잘못된 응답 유형
위 사진에서, MIME Type이 text/plain
으로 응답되는 것을 볼 수 있다.
따라서, 서버에서 응답하는 Content-Type을 text/css
로 응답하도록 수정하여 해결했다.
-> Spring의 ResponseBody에 contentType을 지정하여 반환했다.
suspend fun getCustomCss(request: ServerRequest): ServerResponse {
return withContext({보안상 중략}) {
// 보안상 중략
val cssBody = reactiveStringRedisTemplate.opsForValue()
.get({Redis Key})
.awaitFirstOrNull() ?: {서비스}.getCustomCss(mallNo)
ServerResponse.ok().contentType(MediaType.valueOf("text/css;charset=utf-8")).bodyValueAndAwait(cssBody)
}
}
redis에서 불러오는 것도 handler가 아니라 service단에 넣어야 하나 고민이다..
Reference
https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy
https://ko.wikipedia.org/wiki/JSONP
https://ko.wikipedia.org/wiki/%EC%82%AC%EC%9D%B4%ED%8A%B8_%EA%B0%84_%EC%9A%94%EC%B2%AD_%EC%9C%84%EC%A1%B0
https://velog.io/@logqwerty/CORS#access-control-allow-origin-%EC%99%80-access-control-allow-credentials-true%EB%8A%94-%ED%95%A8%EA%BB%98-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%97%86%EB%8B%A4
Chat GPT