빌드업 - 공공 API 사용

박상하·2024년 11월 27일

BuildUp

목록 보기
3/4

Cors Error 해결

필자가 사용한 공공 API는 2D데이터 API 2.0
해당 API는 지역 시군구를 기준으로 위치값, 광역시도를 기준으로 시군구 정보 등 2D지도 위에서 지역정보를 담는 API이다.

해당 API를 사용하게 될지 확정은 아니지만 일단 사용하지 않더라도 API fetcher 함수를 개발하면서 생긴 이슈이다.

문제는 API의 Cors에러가 발생했다는 점이다.

Cors: Cross-Origin Resource Sharing
결국 같은 URL로 요청을 보내거나
사전에 약속한 URL로 요청을 보내야 한다는 원칙이다.
이를 어기게 되면 Cors Error가 발생한다.
여기서 URL은 더 자세히 (프로토콜, 도메인, 포트번호)를 뜻한다

핵심은 Cors 에러는 브라우저에서만 발생한다는 점이다.
서버간의 교환에서는 Cors 에러가 발생하지 않는다.
즉, 브라우저에서 모르는 출처로부터의 데이터 교환을 막아준다.

만약 내가 API 개발자라고 생각해보자, 그럼 API를 만들어서 데이터를 제공하고 싶은 고객에게만 오픈하고싶지 (허용 cors를 따로 설정한경우) 아무에게나 해당 데이터를 공유할 생각으로 개발하는게 아니다.

API 브라우저로 데이터가 들어갈 경우를 대비하여 일부 출처를 허용해 놓는다. 이러한 측면에서 API가 만들어질 때 한 번 더 보안적인 장치를 두는 것이 "공개키"이다.

우리가 카카오나 네이버 그 외의 다양한 Open API를 사용하면 공개키를 사용하는데 이 역시 누가 요청하는지를 한 번 더 확인하는 과정이라 볼 수 있다.
네이버나 카카오는 모든 출처를 열어두고 공개키만을 사용해 허용된 사용자(브라우저)에서 사용가능하도록 할 수 있다.

자 다시 본론으로 들어와서 정리하자면,

클라이언트 -> API 서버로 데이터 요청 ->
데이터와 Header에 Access-Control-Allow-Origin: "여기에 허용출처"를 담아 보낸다.
-> 브라우저: 데이터 Header에 담긴 Origin을 확인하고 나의 Origin과 같다면 ("*"라면) 해당 데이터를 사용할 수 있는 것이다.

Cors 에러는 브라우저에서 발생하지만 결국 사용자를 위한 보안법이 아닌 API의 데이터를 보호하는 방법이다.

필자가 조금 잘못생각했던 점은 클라이언트의 보안을 위해 Cors에러가 발생한다고 생각했다. 왜냐하면 브라우저에서 발생하니까..!

그런데 API에서 출처를 전부로 열어버리면 요청한 브라우저는 그냥 데이터를 받을 수 있는 것이다. 그렇기에 API의 데이터를 위한 보안방법이다.

해결법: Cors만을 위한 프록시 서버

사용자는 express.js로 간단한 프록시 서버를 개발하였다.
서버-서버간에 출처는 오류가 발생하지 않기때문에
서버1 - API서버의 관계에서 서버1의 출처를 나의 localhost origin을 허용하면
문제없이 사용할 수 있는 것이다.

물론 해당 api를 정말 사용한다면 백엔드 서버를 거쳐 사용하면 될 문제이지만
현재 지금은 백엔드분들께서 세팅을 마치시기 전에 스스로 해보는 과정이기 때문에 다음과 같은 방법으로 해결을 했다.

const API_KEY = "비밀키";
const API_URL = "http://localhost:5173";

app.get(`/regionlocation/:region`, async (req, res) => {
  const { region } = req.params;

  const data = await fetch(
    `https://api.vworld.kr/req/data?service=data&request=GetFeature&data=LT_C_ADSIGG_INFO&key=${API_KEY}&domain=${API_URL}/&format=json&attrFilter=full_nm:like:${region}&geometry=false`
  );
  const regionLocation = await data.json();
  res.json({ regionLocation: regionLocation });
  res.end();
});

app.listen(5005, () => {
  console.log("성공");
});

이런식으로 간단한 프록시 서버를 개발하여 문제를 해결하였다 ⛹️

0개의 댓글