Everyone, really.
0. 왜 작성해야 하는가?
- 스터디 주제!
preflight
는 언제 발생하지?- 왜 IMG, StyleSheet, Script 요청은 CORS를 발생하지 않는가?
1. Process
- SOP : same-origin policy
- CORS: Cross-Origin Resource Sharing
- preflight
- How to solve
2. SOP란?
-
브라우저에서 작동하는 리소스를 처리하는 보안 방식
-
잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄인다
-
프로토콜 / 포트/ 호스트 까지 같은 URL을 동일한 출처라고 말한다.
URL 결과 이유 http://store.company.com/dir2/other.html 성공 경로만 다름 http://store.company.com/dir/inner/another.html 성공 경로만 다름 https://store.company.com/secure.html 실패 프로토콜 다름 http://store.company.com:81/dir/etc.html 실패 포트 다름 (http://는 80이 기본값) http://news.company.com/dir/other.html 실패 호스트 다름
-
-
단, 출처가 다른 것도 허용하는 부분도 있다.
<script> <link> <img> <video> <audio> <object> <embed> @font-face, <iframe>
-
Web Storage와 indexDB 같이 브라우저 데이터 저장소 또한 SOP를 적용받는다.
- Cookie는 SOP 정책에 해당하지 않고, 모든 도메인에 접근하고 설정할 수 있다(그래서 광고 같은데서 쿠키를 활용해서 사용하는것으로 알고 있음) 그래서 쿠키의 정보는 출처가 불분명하므로 안전하지 않다.
3. CORS란?
-
SOP(브라우저 보안방식)에서 발생하는 에러
- 다른 출처로 부터 요청하는 css, js, img 파일은 정상적으로 작동하지만,
- script상에서 다른 리소스를 요청하는 것은 CORS에러가 발생한다.
// localhost:63342/index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="http://localhost:5500/style" rel="stylesheet"> // color: red <script src="http://localhost:5500/js"></script> // console.log('hello Wrold') </head> <body> <h1>Client</h1> <img src="http://localhost:5500/img/1"> <script> (async () => { const result = await fetch('http://localhost:5500/hello') console.log(result.json()) })(); </script> </body> </html>
4. Preflight trigger
모든 Request는 Preflight를 보내는줄 알았는데......... 아니였다...
- Preflight란? 브라우저(클라이언트)는 직접적으로 리소스를 요청을 하기보다는, OPTIONS 메소드를 통해 해당 서버에서 어떤 Method를 허용하는지, 확인하여 리소스를 요청한다.
- 몇가지 조건을 만족해야지 preflight를 trigger된다
- Method : GET / HEAD / POST
- Headers : Accept / Accept-Language / Content-Language / Content-Type
- 클라이언트에서 직접적으로 지정할 수 있는 옵션
- Content-Type 를 지정시(단, 아래 세가지는 발생하지 않는다)
application/x-www-form-urlencoded, multipart/form-data, text/plain
제외
5. How to solve CORS
백앤드를 찾아가서 CORS 오류 난다고 하면? .... 문제 해결
-
백앤드 - Response Header에 해당 속성을 넣어주면 된다
- Access-Control-Allow-Origin를
*
로 하면 모든 request를 열어주는것이므로 보안에 취약하다. 그러므로 서비스하고 있는 client의 url을 넣어주면 gooood
Access-Control-Allow-Origin : * Access-Control-Allow-Method : GET, POST, PUT. DELETE, OPTIONS (디폴트는 GET, POST) Access-Control-Max-age : 3600 Access-Control-Allow-Headers : Origin, Accept, X-Requestd-With, Content-Type,Access-Contorol-Request-Method, Access-Contorol-Request-Header, Authorization Access-Contorol-Allow-Credentials - 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우에 True를 응답받은 클라이언트는 실제 용청시 서버에서 정의도니 규격의 인증값이 담긴 쿠키를 같이 보내야한다.
- Access-Control-Allow-Origin를
-
프론트앤드 - 방법없지만, 잘못된 Header 필드로 보내게 된다면.. CORS가 발생한다.
-
response 부분을 수정하는것이라, 불가능하다.
-
하지만 개발환경일 경우, proxy를 설정하여, 요청 origin을 서버 주소로 바꿔 요청 할 수 있다.
// react cra // package.json { "proxy": "http://localhost:4000" } // src/setupProxy.js const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/api', createProxyMiddleware({ target: 'http://localhost:5000', changeOrigin: true, }) ); };
-
잘못된 Header 필드로 보내게 된다면.. CORS가 발생한다.
const result = await fetch('http://localhost:5000/hello', { headers: { foo: 'bar', // cors Error 'Accept-Manguage': 'en', // cors Error Manguage 오탈자! }, })
-