본문 바로가기
프로그래밍/database

[220307] 서로 다른 서버끼리 통신하기(CORS, Access-Control-Allow시리즈)

by 한코코 2022. 3. 14.

브라우저의 보안을 지켜주는 동일 출처 정책 SOP

기본적으로는 다른 서버끼리는 서로 통신하지 못한다.

4001번 포트로 연결되어있는 서버에서 3001포트로 연결하려고하면 에러가 뜬다.

같은 출처끼리만 리소스 공유나 접근을 허용해주는 동일 출처 정책 때문이다.

//localhost:4001에 연결되어있는 서버
const btn = document.querySelector('#btn')
btn.addEventListener('click',async ()=>{
    alert('버튼클릭')

    let response = await axios.get('http://localhost:3001')
    console.log(response.data)
})

 

출처(Origin)란?

http://127.0.0.1:5500/index.html?<Query>#<Fragment>

scheme(프로토콜) : 브라우저가 사용할 프로토콜

host : 요청이 도달할 서버. 도메인 네임이나 IP adress

port : 서버에서 프로그램(서비스)이 사용하는 소켓을 구분

path : 서버에서 자원의 경로

queryString : ? 이후로 시작. 서버에 전달할 파라미터. key=value 쌍으로 표기하고 복수개의 경우 &로 구분

fragment : html 요소의 id를 가르켜 해당지점으로 스크롤을 이동

 

* 프로토콜 *

컴퓨터 내부에서, 또는 컴퓨터 사이에서 데이터의 교환 방식을 정의하는 규칙 체계.

기기 간 통신은 교환되는 데이터의 형식에 대해 상호 합의를 요구하는데, 이런 형식을 정의하는 규칙의 집합을 뜻함.

 

http://127.0.0.1:5500/index.html?<Query>#<Fragment>

이 중에서 프로토콜, 호스트, 포트를 합친것을 출처(Origin)이라고 한다.

기본적으로는 동일한 출처의 접근만 허용하는 동일 출처 정책(Same-Origin Policy 줄여서 SOP)을 갖추고 있다.

그 이유는 외부의 침입을 차단해 정보의 보안을 지킬 수 있기 때문이다.

하지만 웹페이지는 자신만의 리소스를 가지고 운영하기에는 한계가 있기 때문에 다른 출처의 접근도 허용해야한다.

응답헤더에 정보를 추가해서 코드를 작성하면 다른 서버도 접근이 가능해진다.

app.get('/',(req,res)=>{
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4001')
    //4001 포트와 연결을 허용해주는 코드
    res.send('back index')
})

 

쿠키도 마찬가지!

허락을 받은 사람이나, 자기 자신에게 요청했던 사람에 한해서 쿠키생성을 허락한다.

app.get('/',(req,res)=>{
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4001')
    res.setHeader('Access-Control-Allow-Method', 'POST, GET, OPTIONS, DELETE')

    res.setHeader('Set-cookie','ingoo=name;')
    res.send('back index')
})

쿠키가 생성되지도 않고 다음과 같은 오류코드를 띄운다.

 

쿠키 역시 생성하고 싶다면 응답헤더에 정보를 추가해주면 추가가 가능하다.

//server.js
const express = require('express')
const app = express()

app.use(express.json())
app.use(express.urlencoded({extended:true}))

//비동기통신으로 연결하기전 먼저 물어보는 미들웨어
//내가 요청을 보낼 자격이 되니?
app.use((req,res,next)=>{
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4001')
    //4001 포트와 연결을 허용해주는 코드
    res.setHeader('Access-Control-Allow-Method', 'POST, GET, OPTIONS, DELETE')
    //리퀘스트 메소드의 종류를 인식해주는 코드
    res.setHeader('Access-Control-Allow-Credentials','true')
    //쿠키 생성을 돕는 코드
    res.setHeader('Access-Control-Allow-Headers','Content-type')
    //헤더를 읽을 형식을 돕는 코드
    next()
})

app.post('/',(req,res)=>{
    console.log(req.body)
    res.setHeader('Set-cookie','ingoo=name; Domain=localhost;')//쿠키생성
    res.send('back index')
})

app.listen(3001,()=>{
    console.log('back server!')
})
//index.html
<button id="btn">버튼</button>
<script typt="text/javascript">
    const btn = document.querySelector('#btn')
    btn.addEventListener('click',async ()=>{
        alert('버튼클릭')
        const data = {
            userid:'web7722',
            username:'ingoo'
        }

        const option = {
            method:'POST',
            headers:{'Content-type':'application/json'},
            credentials:'include',
            body:JSON.stringify(data)
        }
        let response = await fetch('http://localhost:3001',option)
        let result = await response.text()
        console.log(result)
    })
</script>

 

다른 서버에 접근해서 리소스를 전달할 수 있는 장점을 얻었지만, 길고 복잡하다는 단점이 있다.

이런 단점을 개선해서 만들어진 라이브러리가 바로 CORS다.

 

CORS란?

CORS는 Cross-Origin Resource Sharing의 약자로,

브라우저에서 다른 출처의 리소스를 공유하는 방법이란 의미를 갖고있다.

간단히 다른 서버끼리 통신을 하게 해주는 라이브러리라고 보면 된다.

외부의 리소스를 사용하기 위해 SOP의 예외적인 케이스가 CORS다.

 

 

CORS 세팅하기

라이브러리이므로 npm을 통해 설치가 가능하다.

$npm install cors

역시 라이브러리므로 사용하기 위해서는 express를 사용해 이식을 해주면 된다

const cors = require('cors')

app.use(cors())
//아래와 같은 구조를 지니고 있으니 익숙해질때까지는 밑에 붙여놓자
// app.use((req,res,next)=>{
//     res.setHeader('Access-Control-Allow-Origin', '*')
//     res.setHeader('Access-Control-Allow-Method', 'POST, GET, OPTIONS, DELETE')
//     res.setHeader('Access-Control-Allow-Credentials','true')
//     res.setHeader('Access-Control-Allow-Headers','Content-type')
//     next()
// })

 

참고 사이트

댓글