Web Server - Node.js

jeongjwon·2023년 4월 4일
0

SEB FE

목록 보기
32/56

SOP

Same-Origin Policy 동일 출처 정책
같은 출처(Origin)의 리소스만 공유가 가능하다.

* 출처(Origin)이란?
프로토콜 + 호스트 + 포트의 조합으로 이 중 하나라도 다르면 다른 출처로 받아들여야 한다.

  • https://www.codestates.com vs http://www.codestates.com
    https vs http 두 URI의 프로토콜이 다름 ➡️ 다른 출처
  • 호스트
    https://urclass.codestates.com vs https://codestates.com
    urclass.codestates.com vs codestates.com 두 URI의 호스트가 다름 ➡️ 다른 출처
  • 포트
    http://codestates.com:81 vs http://codestates.com
    http 프로토콜의 기본 포트는 80이므로 후자의 URI는 http://codestates.com:80 과 같다. :81 vs :80 두 URI의 포트가 다름 ➡️ 다른 출처
  • https://codestates.com:443 vs https://codestates.com 두 URI 는 프로토콜 https 와 호스트 codestates.com 과 포트 :443 이 같음 ➡️ 같은 출처

잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄인다. 다른 사이트와의 리소스 공유를 제한한다. ➡️ 해킹의 위협에서 보다 안전, 보안상 유리



CORS

Cross-Origin Resource Sharing 교차 출처 리소스 공유
추가 HTTP 헤더를 사용하여 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 함. SOP 의 다른 리소스 공유 문제 해결.

http://localhost: 를 fetch하려고 했지만 다른 출처의 리소스를 공유하지 못하는 SOP 때문에 접근 불가하여 CORS 설정을 통해 서버의 응답 헤더에 Access-Control-Allow-Origin을 작성하여 접근 권한을 얻을 수 있다.

CORS 동작 방식

프리플라이트 요청 (Preflight Request)

브라우저는 서버에 실제 요청을 보내기 전에, 프리플라이트 요청(OPTIONS 메서드로 사전 요청을 보내 해당 출처 리소스에 접근 권한이 있는지 확인하는 것)을 보내고, 응답 헤더의 Access-Control-Allow-Origin으로 요청을 보낸 출처가 돌아오면 실제 요청을 보내게 된다.

preflight 요청에 대한 응답을 보낼때는 200의 StatusCode 와 응답헤더를 같이 보내주고
요청 메서드가 POST이나 PUT 일 경우에는 201의 StatusCode 와 요청 바디부분이 중요하다.

만약, 프리플라이트 요청을 보냈지만 접근 권한이 없다면 브라우저에서 CORS 에러를 띄우고 실제 요청은 전달되지 않는다.

  • 실제 요청을 보내기 전에 미리 접근 권한을 확인함으로써 리소스 전달 측면에서 효율적이다.
  • CORS에 대비 되어 있지 않은 서버를 보호할 수 있다.

단순 요청 (Simple Request)

특정 조건이 만족되면 프리플라이트 요청을 생략하고 요청을 보내는 것

인증정보를 포함한 요청 (Credentialed Request)

요청 헤더에 인증 정보를 담아 보내는 요청으로 민감한 정봉기 때문에 프론트와 서버 양측의 CORS 설정이 모두 필요하다.

  • 프론트 측에서는 요청 헤더에 withCredentials:true 추가
  • 서버 측에서는 응답 헤더에 Access-Control-Allow-Credentials: true 추가 (단, * 와일드 카드로 설정할 경우 에러 발생)



CORS 설정 방법

Node.js 서버

http 서버를 만들어 응답 헤더 설정

const http = require('http');

const server = http.createServer((request, response) => {
  //모든 도메인 *
  response.setHeader("Access-Control-Allow-Origin", "*");
  
  //특정 도메인
  response.setHeader("Access-Control-Allow-Origin", "https://codestates.com");
  
  //인증 정보를 포함한 요청을 받을 경우
  response.setHeader("Access-Control-Allow-Origin", "true");
  

Express 서버

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"});
});




[과제1] - Node.js로 Server 구축

  1. Preflight 요청 처리
    preflight 는 요청 메서드가 OPTIONS 로 구분하고, 응답헤더로 Access-Control-Allow-Origin 보내야 한다.
if(request.method === 'OPTIONS'){
    response.statusCode(200);
	response.setHeader(" " , " "); 
  
  //위 코드를 축약하여 writeHead 메서드를 이용해 응답 헤더를 설정할 수 있음
  //응답헤더가 이미 작성되어 있기 때문에 writeHead 메서드 사용
  response.writeHead(200, defaultCorsHeader); 
  response.end();//응답 마침
}
  1. POST 요청 처리
    preflight 가 끝나면 실제 요청이 서버로 보내게 되고 그 실제 요청을 처리하는 응답을 해야 한다. 요청메서드를 POST 로, url로 명령을 구분하여 처리한다.
if(request.method === 'POST' && request.url === '/upper'){
  let body = [];
  
  request.on("data", (chunck) => {
    body.push(chunk);
  }).on("end", () => {
    body = Buffer.concat(body).toString().toUpperCase();
    response.writeHead(201, defaultCorsHeader);
    response.end(body);
  });
}else if(request.method === 'POST' && request.url === '/lower'){
  ...
}

대문자로 바꾸어주는 작업은 HTTP 트랜잭션 해부 | Node.js 에 잘 나와있는데,
특히나 메서드가 POST 나 PUT 은 요청 바디가 포함되어 있기 때문에 요청 바디의 데이터를 받는 작업이 중요하다.

핸들러에 전달된 request 객체는 ReadableStream 인터페이스를 구현하고 있다. 이 스트림에 이벤트 리스너를 등록하거나 다른 스트림에 파이프로 연결할 수 있다. 스트림의 'data'와 'end' 이벤트에 이벤트 리스너를 등록해서 데이터를 받을 수 있습니다.

  • request.on("data", ) : 요청에서 데이터가 도착했을 때를 의미하며 발생시킨 chunk는 Buffer로 나누어져서 전달된다. 이 청크가 문자열 데이터라는 것을 알고 있다면 이 데이터를 배열에 수집한 다음 'end' 이벤트에서 이어 붙인 다음 문자열로 만든다.
  • request.on("end", ) : 요청에서 데이터가 다 전달됐을 때를 의미한다.

3. error 처리 나머지 else 로 분류하여 처리하는데 응답헤더의 StatusCode가 404인 것이 중요하다.
response.writeHead(404, defaultCorsHeader);
response.end();




Access-Control-Allow-Origin : http://localhost:5100 으로 설정해놓은 상태에서

당연히 http://localhost:5100 으로 접속하고 요청하면 응답하지만,


http://localhost:5200 으로 접속하면 CORS 설정을 다시하여 접근권한을 부여해라는 에러 메세지가 뜬다.

이로써 CORS와 SOP에 대한 서버 접근 권한을 알아 볼 수 있었다.





서버 부분이 항상 개념이 잡히지 않아서 백엔드 대신 프론트엔드를 선택한 것도 있지만, 이렇게 작게 나마 개념을 알게 되서 다행이라고 생각한다. 그치만 내가 이해한 것이 제대로 이해한 것이 맞나? 라는 의구심이 들기도 하지만, 라이브 세션에서 자세히 들어봐야 또 알 것 같다.

0개의 댓글