[WEB SERVER]CORS
SOP(Same-Origin Policy 동일 출처 정책)
같은 출처(Origin)의 리소스만 공유 가능
보안을 위해
출처(Origin) - 포로토콜, 호스트, 포트의 조합
즉, 하나만 다르더라도 다른 출처
하지만 다른 출처의 리소스를 사용해야하는 경우가 많기 때문에 CORS 사용
CORS(Cross-Origin Resource Sharing)
추가 HTTP 헤더으로 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여
동작방식
-
프리플라이트 요청(Preflight Request)
OPTUION 메서드로 사전 요청을 보내 해당 출처 리소스 접근 권한 확인
접근 권한이 없다면 서버가 브라우저로 응답없음을 Response하고 브라우저는 클라이언트에 CORS에러를 띄움
- 사전 권한 확인으로 효율적
- CORS에 대비가 되어있지 않은 서버 보호
-
단순 요청(Simple Request)
조건
- GET, HEAD, POST 요청 중 하나
- 자동으로 설정되는 헤더 외에, Accept, Accept-Language, Content-Language, Content-Type 헤더의 값만 수동으로 설정 가능
- Content-Type 헤더에는 application/x-www-form-urlencoded, multipart/form-data, text/plain 값만 허용
- Content-Type 헤더에는 application/x-www-form-urlencoded, multipart/form-data, text/plain 값만 허용
-
인증정보를 포함한 요청(Cedentialed Request)
요청 헤더에 인증 정보를 담아 보내는 요청
프론트, 서버 양측 모두 CORS 설정이 필요
- 프론트: 요청 헤더에 withCredentials : true
- 서버: 응답 헤더에 Access-Control-Allow-Credentials : true
- 서버 측에서 Access-Control-Allow-Origin 을 설정할 때, 모든 출처를 허용한다는 뜻의 와일드카드(*)로 설정하면 에러가 발생
CORS 설정방법
Node.js
응답해더 설정
const http = require("http");
const server = http.createServer((request, response) => {
// 모든 도메인
response.setHeader("Access-Control-Allow-Origin", "*");
// 특정 도메인
response.setHeader("Access-Control-Allow-Origin", "https://naver.com");
// 인증 정보를 포함한 요청을 받을 경우
response.setHeader("Access-Control-Allow-Credentials", "true");
});
Express(프레임워크) 서버
cors 미들웨어를 사용, 간단하게 CORS 설정 가능
const cors = require("cors");
const app = express();
//모든 도메인
app.use(cors());
//특정 도메인
const options = {
origin: "https://codestates.com", // 접근 권한을 부여하는 도메인
credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
optionsSuccessStatus: 200, // 응답 상태 200으로 설정
};
app.use(cors(options));
//특정 요청
app.get("/example/:id", cors(), function (req, res, next) {
res.json({ msg: "example" });
});
브라우저에는 서버에 요청을 보내기 위해 fetch 같은 HTTP 요청을 보내는 도구가 내장.
서버는 클라이언트(브라우저)의 HTTP 요청에 맞게 응답을 보낼 수 있도록 코드를 작성.
Node.js는 HTTP 요청을 보내거나, 응답을 받을 수 있는 도구 제공.
HTTP 요청을 처리하고 응답을 보내 주는 프로그램 - 웹 서버(Web Server)
모든 node 웹 서버 애플리케이션은 웹 서버 객체를 만들어야 함. 이 때 createServer를 이용.
const http = require("http");
const server = http.createServer((request, response) => {
// 여기서 작업
});
이 서버로 오는 HTTP 요청마다 createServer에 전달된 함수가 한 번씩 호출. createServer가 반환한 server 객체는 EventEmitter이고 여기서는 server 객체를 생성하고 리스너를 추가하는 축약 문법을 사용.
const server = http.createServer();
server.on("request", (request, response) => {
// 여기서 작업
});
HTTP 요청이 서버에 오면 node가 트랜잭션을 다루려고 request와 response 객체를 전달, 요청 핸들러 함수를 호출.
CORS 설정방법
if (request.method === "OPTIONS") {
response.writeHead(200, defaultCorsHeader); // HTTP Status Codes / 200 - OK (GET) 요청의 성공
response.end(); // GET, HEAD, DELETE, OPTIONS 등 서버에 리소스 요청 경우 body가 필요하지 않음
}
핸들러에 전달된 request 객체는 ReadableStream 인터페이스를 구현. 이 스트림에 이벤트 리스너를 등록하거나 다른 스트림에 파이프로 연결 가능. 스트림의 ‘data’와 ‘end’ 이벤트에 이벤트 리스너를 등록해서 데이터를 받을 수 있음
let body = '';
if(// request로 받아온 method와 url의 조건) {
request.on('data', (chunk) => { // 데이터 이벤트 발생
body += chunk;
})
request.on('end', () => { // 엔드 이벤트 발생
const data = body.toLowerCase(); // 데이터를 담는다
response.writeHead(201, defaultCorsHeader); // 헤드
response.end(data); // 엔드
})
문자열이 길지 않아 chunk에 한번에 들어가기 때문에 concat을 안해줬을 때도 toLowerCase 메서드로 한번에 처리가 되지만, 긴 데이터 입력했을 때는 데이터를 전부 다 받아왔을 때 end에서 toLowerCase를 처리해야 된다.
요청을 실제로 처리하려면 listen 메서드가 server 객체에서 호출되어야함. 대부분은 서버가 사용하고자 하는 포트 번호를 listen에 전달하기만 하면 됨.
server.listen(PORT, ip, () => {
console.log(`http server listen on ${ip}:${PORT}`);
});
preflight request에 대한 응답 헤더
const defaultCorsHeader = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Accept",
"Access-Control-Max-Age": 10,
};
https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction/
간단한 서버제작
index.js 파일일을 만들고
const http = require("http");
const server = http
.createServer((req, res) => {
res.end("hello");
})
.listen(8080);
console.log("8080 포토에 서버가 작동 됩니다");
CLI에서 node index.js 실행
8080은 서버 자체에 접속하는 것이다. 즉 서버가 작동하는지 확인이 가능하고 클라이언트에게는 전달되지 않는다.
buffer 임시 데이터 저장소
chunk는 데이터의 조각 이 조각들이 합쳐져서 buffer가 된다.
chunk를 buffer에 다 채우고 다 차면 buffer를 통째로 옮기고 이런 작업을 연속하는 것이 stream 이다.
댓글남기기