안녕하세요.
Hynn 입니다.
이번 포스팅에서는 CORS 에 대해서 다루어 보도록 하겠습니다.
다음 포스팅에서 사용하고자 하는 AJAX 기능을 구현하기에 앞서, 이제 서버를 현재 시스템의 구조 형태로 설정을 할 예정입니다.
그를 이해하기 위해서는 CORS 가 반드시 알아야 하는 개념으로 이에 대한 개념을 먼저 학습할 예정입니다.
==============
1. CORS 란 무엇인가요?
2. CORS 의 출처 확인방법
3. 실제 Server 간 CORS 설정하기 예제
==============
1. CORS 란 무엇인가요?
CORS(Cross-Origin Resource Sharing) 은, 웹 페이지가, 타 도메인에 요청하는 것을 차단하는 보안기능입니다.
이는 타 사이트의 정보를 무단으로 가져오거나, 피싱같이 악용될 소지가 다분한 요청들이 포함될 수 있기 때문에,
수행되는 중요한 기능입니다.
예를 들자면, 제가 하나의 포털 사이트 (가칭. 너이버닷컴) 을 운영하는 개인 사업자라고 가정합니다.
여기서 제가 개발비용이 혼자서 하기에는 서버비용이나, 유지비용이 적지 않기 때문에, 네이버의 정보들을 무단으로 사용하기 위해서 이 소스코드를 제 포털 사이트에 다 구현을 한다면, 저는 적은 비용으로 양질의 포털 사이트를 하나 만드는 셈이 됩니다.
이렇게 되면 이는 분명히 악의적인 구현 방법이 될 것입니다.
CORS 는 바로 이러한 허용되지 않아야 하는 연결을 차단하고 오류를 반환함으로써, 기능이 작동하도록 설계된 보안방법입니다.
이 보안방법은 표준화가 되어 있는 규정이 존재합니다.
바로 아래의 두가지가 그것입니다.
RFC6454 - The Web Origin Concept
W3C - Cross-Origin Resource Sharing
2. CORS 의 출처 확인방법
기본적으로 CORS 의 정책은 SOP(Same-Origin Policy) 의 정책에서부터 출발합니다.
즉, 이 정책의 핵심은 "a security feature implemented by web browsers to prevent web pages
from making requests to a different domain than the one that served the web page"
이 정책의 핵심적사항은 "같은 출처에서만 리소스를 공유할 수 있습니다" 라는 기본 규칙에서 출발합니다.
하지만 이 정책만 본다면 의아한 상황들을 많이 접했으리라 생각합니다.
바로 잘 알려지지 않은 웹 사이트 조차도, 쉽게 보면 카카오, 구글, 애플, 네이버를 사용한 로그인을 구현하고 있는 웹 페이지가 당장 주변만 보더라도 수를 셀수 없을 만큼 많이 존재합니다. 이런것을 보면 이 정책을 한국만 적용하고 있지 않을까요? 그것은 아닙니다.
바로 이에 대한 예외조항이 "CORS" 입니다. 이 표준 문서에서도 몇가지 예외적 조항을 가지고 이 예외조항에 해당한다면 출처가 다르더라도 허용하는 정책을 표준으로 사용하고 있습니다. 바로 그것이 "CORS 를 준수한 리소스 요청" 일 경우에 한해서 입니다.
이에 대한 같은 출처와 다른 출처에 대한 구분은 아래와 같이 표시하고 있습니다.
예를 들어 홈페이지를 하나 예시로 작성해보도록 하겠습니다.
예시를 든 홈페이지는 바로 제 GitHub 주소입니다.
https://github.com/Hynn-Hyunwoong?tab=repositories
부끄럽지만 제 GitHub 의 Repository 의 주소입니다.
이것을 가지고 몇개 의 정보를 구성해보도록 하겠습니다.
https://github.com/Hynn-Hyunwoong?tab=repositories
Hynn-Hyunwoong - Overview
Hynn-Hyunwoong has 8 repositories available. Follow their code on GitHub.
github.com
위의 색깔을 나누어 실제 우리가 사용하는 웹 사이트의 구조를 표시했습니다.
- Scheme : 홈페이지의 구성요소인 Http:// , Https:// Ftp:// 와 같은 프로토콜을 정의합니다.
- Host : 서버의 도메인이름입니다. 여기서 도메인은 당연히 Github가 되겠습니다.
- Port : 포트는 일반적으로 URL 에 따라 기본 포트가 지정됩니다. http 일경우 80, https 의 경우 443이 지정됩니다. 이 사이트의 경우 포트가 표시되지 않아, 위의 기본 포트체계로 이루어지나, 만약 우리가 VisualStudio Code 를 사용할 때 "http://127.0.0.1:3000 " 이라고 지정했다면, 이 경우는 포트가 기본체계가 아닌 명시적으로 "3000"이 포트가 됩니다.
- Path : 서버에서 리소스의 위치를 지정합니다. 일반적으로 "/" 으로 표기되며, 이전에 코드 작성에서 app.get 등으로 표기한 바 있습니다.
- Query-string : 일반적으로 웹 페이지에서 서버로 데이터를 보내거나 서버의 특정 리소스를 식별하는데 사용됩니다. 일반적으로 ?가 시작점이 됩니다. 쿠키나, 인덱스값을 이용해서 특정 페이지를 구분하기도 합니다.
즉, 여기서 이야기하는 "출처가 같은 리소스" 를 구분하는 정의는 바로, "Scheme, Host, Port" 이 3가지가 일치해야 합니다.
또한 이러한 CORS 의 대한 최종 판단은 바로 "브라우저"가 한다는 것이 핵심입니다.
이를 그림으로 표현하면 아래와 같이 표현이 가능합니다.
즉 표준화된 이 정책에서는, 서버간의 통신자체를 서버에서 차단하는 것은 아닙니다.
하지만 Client 가 서버에 요청하고, 서버는 그 데이터를 다시 Client 에 전달하면, 그 데이터에는 바로 "Header" 라는 녀석이 포함됩니다.
이미 여러분들이 많이 보아왔던 것입니다. 바로 아래 사진의 이것입니다.
지금 위의 헤더에 이러한 정보가 포함이 되어 있습니다.
즉, 여기서 허용이 되어 있지 않은 정보를 수신했다면 "브라우저"가 이를 차단해버리면서 오류를 일으킵니다.
아마 앞으로도 개발을 하시고자 하는 분들이라면 많이 접하게 될 문구라고 합니다.
Access to XMLHttpRequest at 'http://localhost:3000/users'
from origin 'http://127.0.0.1:3005'
has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
즉 여기서 저는, 127.0.0.1:3005 라는 서버를 구동했고, 다른 출처를 가진 127.0.0.1:3000 서버의 데이터를 가져오고자 했습니다.
하지만 CORS 정책으로 데이터는 주고받았더라도, 브라우저에서 허용되지 않았기 때문에, 이를 차단한 것입니다.
만약 이를 정상적으로 허용을 했다면, 아래의 내용이 헤더에 포함됩니다.
이제 이를 기초적으로 작성해보도록 하겠습니다.
3. 실제 Server 간 CORS 설정하기 예제
이 서버는 포트번호를 기준으로 아래와 같이 가정하겠습니다.
- Front-End Server : Port Number 3005
- Back-End Server : Port Number 3000
실제 사용자가 3005번 포트를 가진 웹에 접속해서 작업을 한다면, 여기서의 설정은 3000번의 포트번호를 가진 Back-End 에서 구성해야 합니다.
이를 위해 NPM Module 을 설치해야 합니다.
npm install cors
그리고 일반적으로 작성한 기본적인 서버를 구성하기 위한 자바스크립트 코드를 작성해보겠습니다.
const express = require('express')
const app = express('app')
app.use(express.urlencoded ({extended : false});
app.get("/", (req,res) => {
res.render('index.html')
})
app.listen(3000, () => {
console.log('server start')
})
이제 설치한 CORS Module 을 적용해야 합니다.
const express = require('express')
const cors = require('cors')
const app = express('app')
app.use(express.urlencoded ({extended : false});
app.use(cors())
app.get("/", (req,res) => {
res.render('index.html')
})
app.listen(3000, () => {
console.log('server start')
})
기초적인 설정이 모두 끝났습니다.
단, 이렇게 설정할 경우 헤더에서 전체 허용을 의미하는 " * "로 표기가 될 것입니다.
이후에 실무에서 적용할 것이라면, 허용하는 도메인을 지정해야 할 것입니다. * 표기로 전체를 허용할 경우, 이러한 보안정책을 스스로 버리는 행위가 될 수 있기 때문입니다.
이제 다음 포스팅에서는 프론트와 백엔드 서버를 나누어 AJAX 라고 하는 비동기 코드에 대한 학습을 진행해보도록 하겠습니다.
감사합니다.
'개발공부일지 > NodeJS' 카테고리의 다른 글
NodeJS - .ENV 를 이용해 환경변수 관리하기 (DOTENV) (0) | 2023.01.10 |
---|---|
NodeJS - Ajax실제 작성예시 따라해보기 (0) | 2023.01.08 |
Node.JS - Async/Await 이해하기 (1) | 2022.12.23 |
Node.JS - Promise Object 이해하기 (0) | 2022.12.23 |
Node.js - Express,Nunjucks 를 이용해서 기본 웹 서버 만들어보기 (0) | 2022.12.23 |
댓글