[개발자되기: Web server 기초] Day-31

Kyoorim LEE·2022년 6월 20일
1

SOP (Same-Origin Policy)

동일출처 정책: 같은 출처(origin)의 리소스만 공유가 가능함

출처 : 프로토콜, 호스트, 포트

이중 하나라도 다르면 동일한 출처로 보지 않음
ex)
동일하지 않은 프로토콜 : https://www.codestates.com vs http://www.codestates.com
동일하지 않은 호스트: https://urclass.codestates.com vs https://codestates.com
동일하지 않은 포트 : http://codestates.com:81 vs http://codestates.com
동일한 포트(https 프로토콜의 기본포트는 443): https://codestates.com:443 vs https://codestates.com

동일출처 정책이 생겨난 배경

  • 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄임 => 해킹의 위협에서 보다 안전해질 수 있음 (다른 사이트와의 리소스 공유를 제한하기 때문에 로그인 정보가 타 사이트의 코드에 의해 새어나가는 것을 방지할 수 있음)

CORS (Cross-Origin Resource Sharing)

교차 출처 리소스 공유는 추가 HTTP 헤더를 사용하여 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려줌

CORS 동작 방식

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

실제 요청을 보내기 전, OPTIONS 메서드로 사전 요청을 보내 해당 출처 리소스에 접근 권한이 있는지부터 확인하는 것

<요청 보낸 출처가 접근권한이 없는 경우>

프리플라이트 요청이 필요한 이유

  • 실제요청보내기 전 미리 권한 확인할 수 있으므로 리소스 측면에서 효율적
  • CORS에 대비되어있지 않은 서버를 보호할 수 있음

2. 단순 요청 (Simple Request)

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

특정조건

  • GET, HEAD, POST 요청 중 하나여야 함
  • 자동으로 설정되는 헤더 외에 Accept, Accept-Language, Content-Language, Content-Type 헤더의 값만 수동으로 설정
  • Content-Type 헤더에는 application/x-www-form-urlencoded, multipart/form-data, text/plain 값만 허용

3. 인증정보를 포함한 요청 (Credential Request)

요청 헤더에 인증정보를 담아보내는 요청. 민감한 정보이므로 출처가 다를 경우 별도의 설정을 하지 않으면 쿠키를 보낼 수 없음. 이 경우 프론트, 서버 양측 모두 CORS 설정 필요

  • 프론트 측에서는 요청 헤더에 withCredentials : true 를 넣어줌
  • 서버 측에서는 응답 헤더에 Access-Control-Allow-Credentials : true 를 넣어줌
  • 서버 측에서 Access-Control-Allow-Origin 을 설정할 때, 모든 출처를 허용한다는 뜻의 와일드카드(*)로 설정하면 에러가 발생 (인증 정보인 만큼 정확하게 설정 필요)

CORS 설정 방법

1. 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://codestates.com");
//
// 인증 정보를 포함한 요청을 받을 경우
  response.setHeader("Access-Control-Allow-Credentials", "true");
})

2. Express 서버

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

Refactor Express

Express: Node.js 환경에서 웹서버 또는 API서버를 제작하기 위해 사용되는 인기있는 프레임워크

  • 미들웨어를 추가할 수 있음
  • 라우터를 제공

간단한 웹서버 만들기

const express = require('express')
const app = express()
const port = 3000
//
app.get('/', (req, res) => {
  res.send('Hello World!')
})
//
app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

라우팅: 메서드와 url(/lower, /upper 등)에 따라 분기(Routing)하기

순수 Node.js로 라우팅 구현 시

const requestHandler = (req, res) => {
  if(req.url === '/lower') {
    if (req.method === 'GET') {
      res.end(data)
    } else if (req.method === 'POST') {
      req.on('data', (req, res) => {
        // do something ...
      })
    }
  }
}

Express로 라우팅 구현 시

const router = express.Router()
//
router.get('/lower', (req, res) => {
  res.send(data);
})
//
router.post('/lower', (req, res) => {
  // do something
})

Middleware 미들웨어

미들웨어 사용하는 상황

  1. POST 요청 등에 포함된 body(payload)를 구조화할 때(쉽게 얻어내고자 할 때)
  2. 모든 요청/응답에 CORS 헤더를 붙여야 할 때
  3. 모든 요청에 대해 url이나 메서드를 확인할 때
  4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때

1. POST 요청 등에 포함된 body(payload)를 구조화할 때

Node.js로 HTTP 요청 body를 받는 코드

let body = [];
request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  body = Buffer.concat(body).toString();
  // body 변수에는 문자열 형태로 payload가 담겨져 있습니다.
});

body-parser를 미들웨어로 이용한 코드 (npm install body-parser)

const bodyParser = require('body-parser');
const jsonParser = bodyParser.json();
// 생략
app.post('/users', jsonParser, function (req, res) {
//
})

express.json()을 이용한 코드

const jsonParser = express.json();
// 생략
app.post('/api/users', jsonParser, function (req, res) {
})

2. 모든 요청/응답에 CORS 헤더를 붙일 때

Node.js에 CORS를 적용하는 예시

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
};
// 생략
if (req.method === 'OPTIONS') {
  res.writeHead(201, defaultCorsHeader);
  res.end()
}

모든 요청에 대해 CORS 허용

const cors = require('cors');
// 생략
app.use(cors());

특정 요청에 대해 CORS 허용

const cors = require('cors')
// 생략
app.get('/products/:id', cors(), function (req, res, next) {
  res.json({msg: 'This is CORS-enabled for a Single Route'})
})

3. 모든 요청에 대해 url이나 메서드를 확인할 때

  • 출처: 코드스테이츠

use메서드 이용하여 모든 요청에 대해 미들웨어 적용

const express = require('express');
const app = express();
//
const myLogger = function (req, res, next) {
  console.log('LOGGED');
  next();
};
//
app.use(myLogger);
//
app.get('/', function (req, res) {
  res.send('Hello World!');
});
//
app.listen(3000);

4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인 시

토큰을 통해 로그인 여부 확인하는 미들웨어

app.use((req, res, next) => {
  // 토큰이 있는지 확인, 없으면 받아줄 수 없음.
  if(req.headers.token){
    req.isLoggedIn = true;
    next();
  } else {
    res.status(400).send('invalid user')
  }
})
profile
oneThing

0개의 댓글