WEB Server 기초

햄은 개발 공부중·2023년 2월 8일
0
post-thumbnail

CORS

학습 목표 ✏️

  • SOP에 대한 이해
  • CORS의 정의와 동작 방식에 대한 이해
  • CORS 설정 방법 이해

SOP (same origin policy 동일 출처 정책)

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

CORS (cross origin resource sharing 교차 출처 리소스 공유)

  • 브라우저는 SOP에 의해 기본적으로 다른 출처의 리소스 공유를 막지만, CORS를 사용하면 접근 권한을 얻을 수 있게됨!
  • 위 같은 에러 발생은 SOP에 의해 접근이 불가능해 발생한 에러이다
  • 이때 CORS 설정을 통해 서버의 응답 헤더에 ‘Access-Control-Allow-Origin’ 를 작성하면 접근 권한을 얻을 수 있음!

CORS 동작 방식

  1. 프리플라이트 요청 (Preflight Request)
  • 실제 요청 보내기 전에 OPTION 메서드로 사전 요청을 보내 해당 출처 리소스에 접근 권한이 있는지부터 먼저 확인하는 것
  • 브라우저는 서버에 실제 요청을 보내기 전에 프리플라이트 요청을 보내고, 응답 헤더의 Access-Control-Allow-Origin으로 요청을 보낸 출처가 돌아오면 실제 요청을 보내게됨
  • 만약에 요청을 보낸 출처가 접근 권한이 없다면 브라우저에서 CORS 에러를 띄우게 되고, 실제 요청은 전달되지 않음!
  1. 단순 요청 (Simple Request)
  • 단순히 "특정 조건" 이 만족되면 프리플라이트 요청을 생략하고 바로 요청을 보내는 것
  • 특정조건 : GET, HEAD, POST 요청 중 하나 / Accept, Accept-Language, Content-Language, Content-Type 헤더의 값만 수동으로 설정 가능 / Content-Type 헤더에는 application/x-www-form-urlencoded, multipart/form-data, text/plain 값만 허용
    (위의 조건들을 모두 만족시키기는 어려우니 참고만!)
  1. 인증정보를 포함한 요청 (Credentialed Request)
  • 요청 헤더에 인증 정보를 담아 보내는 요청으로, 출처가 다른 경우 별도의 설정을 하지 않으면 쿠키를 보낼 수 없음(민감한 정보이기 때문!) 이러한 경우엔 프론트, 서버 양측 모두 CORS 설정 필요!
  • 프론트 측에서는 요청 헤더에 withCredentials : true 넣어주기
  • 서버 측에서는 응답 헤더에 Access-Control-Allow-Credentials : true 넣어주기

CORS 설정 방법

  1. Node.js 서버
    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-Credentials", "true");
    })```
    
  2. Express 서버
    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" });
});

Express

  1. 간단한 웹서버 만들기

    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}`)
    })```
    
  2. 라우팅 (메서드와 url에 따라 분기 나누기)

  • 메서드와 url(/lower, /upper 등)로 분기점을 만드는 것을 라우팅(Routing)이라고 함
  • Express는 프레임워크 자체에서 라우터 기능을 제공해 더 직관적인 코드를 작성 가능!
    const router = express.Router()
    router.get('/lower', (req, res) => {
     res.send(data);
    })
    router.post('/lower', (req, res) => {
     // do something
    })```

Middleware

미들웨어(Middleware)는 자동차 공장의 공정과 비슷하다. 컨베이어 벨트 위에 올라가 있는 요청(Request)에 필요한 기능을 더하거나, 문제가 발견된 불량품을 밖으로 걷어내는 역할을 한다. 미들웨어는 express의 가장 큰 장점이라고 할 수 있다.

  1. 미들웨어를 사용하는 상황
  • POST 요청 등에 포함된 body를 구조화할 때(쉽게 얻어내고자 할 때)
    const jsonParser = express.json();
    // 생략
    app.post('/api/users', jsonParser, function (req, res) {
    })```
    
  • 모든 요청 / 응답에 CORS 헤더를 붙여야 할 때 (writeHead 메서드 사용!)
const cors = require('cors');
// 생략
app.use(cors()); //모든 요청에 대해 CORS 허용
//
app.get('/products/:id', cors(), function (req, res, next) {
  res.json({msg: 'This is CORS-enabled for a Single Route'})
}) // 특정 요청에 대해 CORS 허용
  • 모든 요청에 대해 url이나 메서드를 확인할 때 (app.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);```
    
  • 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때 (토큰을 통해서 주로 사용자 인증에 사용)
    app.use((req, res, next) => {
    // 토큰이 있는지 확인, 없으면 받아줄 수 없음.
    if(req.headers.token){
      req.isLoggedIn = true;
      next();
    } else {
      res.status(400).send('invalid user')
    }
    })
  
profile
내가 보려고 정리하는 블로그🔥

0개의 댓글