본문 바로가기
42

Api key 적용하기

by jay-choe 2021. 8. 22.

배경

방문 예약 시스템에서는 방문 예약시 서버에서 URL Shortener api를 사용해서, 단축 Url을 만듭니다. 하지만, 아무런 제약이 없어서 누구나 호출해서 사용 할 수 있었습니다. 만약 악의적인 사용자가 있다면 우리서버에서 돌아가고 있는, 단축 URL 서비스를 마음대로 이용 할 수 있는 상황이었으며, 이 API를 우리 어플리케이션에서만 혹은 우리가 지정한 사용자만 호출 할 수 있게 하고 싶었습니다.

- 우리 어플리케이션 외부(Postman)에서도 api가 정상적으로 호출되는 모습

API 인증방식

api 호출을 인가하는 방식에는 여러가지가 있습니다. (참고)

대표적으로

  1. HTTP Basic Authentication
  2. OAuth 2.0 (Token in HTTP Header).
  3. API Keys

가 있으며, 하나씩 살펴보면,

 

1. Http Basic Authentication

ID,PW 정보를 HTTP Header에 Base 64 인코딩 형태로 넣어서 인증에 사용하는 방법입니다.

즉, Header에 id:password 를 Base 64 인코딩 해서, 전송을 하면, 서버에서 해당 내용을 디코딩 해서 유효한지 체크를 하는 방식 입니다.

이 방식은 간단하다는 장점이 있지만, Base64 인코딩 자체가 강력한 암호화 알고리즘이 아니고, 매번 id, password를 인코딩 해서보내고, 매번 디코딩 해야 한다는 단점이 있습니다.



2. Oauth2.0

Oauth2.0에 관해서 자세한 내용을 다루면 주제를 넘어서기때문에, 어떻게 사용되는지만 보겠습니다.

api를 사용하기 위해서, 클라이언트에서 Oauth provider에 사용자 인증을 하고, 받는 access token을 통해서, api를 요청 할 때,

Oauth provider에서 해당 access token을 검증 후, 유효한 경우에 api를 호출 할 수 있게 하는 구조입니다.

이 방식의 장점은 안전하다는 것 입니다. Oauth provider에게 인증을 받기 때문에, api서버 측에서는 인증을 담당할 필요가 없으며, api 호출시 토큰을 탈취 당하는 일이 있더라도, 사용자의 id와 비밀번호는 탈취되지 않습니다.

 

3. API Keys

 

 API서비스는 API 키(Key)를 요구하도록 일부분 또는 전체를 제한할 수 있으며, API 키(Key)란 특정 사용자만 알 수 있는 일종의 문자열입니다.

API Key 인증 방식은 먼저, 서비스 제공자에게  API Key를 발급 받습니다. (이 과정에서 서비스 제공자에게 사용자 인증을 합니다.)

사용자는 요청시마다, 해당 API Key를 같이 전송을 합니다.

서버는 해당 API Key가 유효한지 체크를 하고, 유효할시 API사용을 인가합니다.

 

구글 클라우드 문서에 따르면 API 키는 다음을 제공합니다.

  • API 키는 API를 호출하는 호출 프로젝트(응용 프로그램 또는 사이트)를 식별합니다.
  • API 키는 호출하는 애플리케이션이 API를 호출할 수 있는 권한이 부여되었고 프로젝트에서 API가 활성화되었는지 확인합니다.
  •  API 키는 호출하는 프로젝트를 식별하지만 호출 사용자는 식별하지 않습니다. 예를 들어 API를 호출하는 애플리케이션을 만든 경우 API 키는 호출하는 애플리케이션을 식별할 수 있지만 애플리케이션을 사용하는 사람의 ID는 식별할 수 없습니다.

 

API 키 사용

 

 API Key는 인증 이외에도 다양하게 쓰일 수 있습니다.

 

- 사용량 체크

구글 API 사용량 및 요금

마찬가지로 API 키를 통해서 키를 발급받은 유저의 API의 사용량을 체크 할 수 있으며, 유료API 서비스같은경우

사용량이 곧 요금이기 때문에 이를 체크할 수 있는 수단인 API Key가 필요합니다.

 

- 사용량 제한(Rate Limit)

API Key를 통해서 API 별 사용량을 제한 할 수 있으며 이를통한 효과는 다음과 같습니다. 참고

  1. DDoS 공격으로 부터 서비스를 보호한다.
  2. API 클라이언트 간에 API Resource의 사용에 공평성을 제공한다. 가령, 소수의 Heavy 클라이언트로 인해 다른 선량한 클라이언트가 피해를 입지 않도록 말이다.
  3.  API를 통해 받는 데이터 자체가 돈과 직결되는 경우, 그 비즈니스 모델로서의 역할을 한다.

이 부분은 해당 포스트에서 다루지 않고 추후에 따로 다루도록 하겠습니다.

 

 

API Key 적용하기

 

1. 키 생성

 서비스를 제공자들은 해당 서비스의 웹 사이트에서 키를 발급하고, 사용자는 이 키를 기반으로 API 요청을 하는 구조로 되어있습니다.

구글이 제공하는 API Key를 예를 들어보면 로그인 한 사용자, 즉 구글 측에서 인증이 완료된 사용자는 API Key를 생성 할 수 있습니다.

추가적으로 구글에서는 API Key에 특정 웹 사이트나, 아이피 주소, 앱에서만 사용할 수 있도록 제한사항을 줄 수 있습니다.

카카오 같은 경우도 마찬가지로 사이트에서 키 등록을 하고, 특정 IP 주소만 호출 할 수 있도록 제한을 걸 수 있도록 되어있습니다.

다른 서비스는 키별로 다른 권한을 부여하는 것을 확인했습니다.

 

서비스들을 보면 생각해봐야 할 부분이 2가지가 있습니다.

 

 첫번째로는, 해당 키의 스코프를 설정하는 것 입니다. 예를들어 특정 아이피 에서만 해당 키를 이용해서 호출을 할 수 있다던지 키별 권한을 부여한다던지 키의 역할 및 호출되는 범위를 정하는 것 입니다. 이 부분은 데이터베이스 스키마의 칼럼을 조정하는 식으로 해결 할 수 있을 것 같습니다. 예를들어 호출 될 수 있는 범위를 아이피 지정방식으로 정했다면, allowed_ip 와같은 칼럼을 만들거나, 허용 아이피가 많아진다면 테이블을 만들어서 조인하는 형태로 줄 수 있을 것 같습니다. 마찬가지로 해당 키의 역할도, 칼럼 하나로 해결할 수 있을 것 입니다.

 

 두번째로는 키값을 어떻게 정할지 입니다.

위의 카카오 같은 경우에는 문자열들이 16진수로 딱 맞아 떨어지는걸로 봐서, 해시값을 전달하는 것으로 보여집니다. 하지만 구글 같은경우는 렌덤의 문자열이고 중간에 구분자가 들어가있는 것을 확인 할 수 있습니다. 카카오가 사용한 헤시 값의 경우 32자 이므로, 128 bits 해시 알고리즘을 사용을 한 것을 확인 할 수 있고, 구글의 키 같은 경우는 구분자(-)를 경계로 글자가 앞에는 7자 뒤에는 25자이상으로 나뉘는데 해시 알고리즘(16진수)보다 더 많은 값을 표현하는 Base62로 표현이 되는데 둘 다 충분히 긴 것을 확인 할 수 있었습니다.

결론적으로는 API Key provider들 마다 다릅니다. 하지만 공통점을 추출해보면, 충분히 길다는 점으로 미루어 보아, 추측이 불가능 하다는 점만 만족시킨다면 어떤 알고리즘을 쓰던지 상관이 없다고 생각했습니다. 따라서 저는 62자의 문자(0-9, a-z, A-Z)를 렌덤으로 추출해서 32글자를 만들었습니다(렌덤 문자 추출 사이트).

 

2. 키 사용하기

  요청시 키를 같이 전달할 방법에는 여러가지가 있지만(쿼리스트링, JSON, Authorization 해더 등), 커스텀 해더인 X-API-KEY 해더에 키 값을 넣어서 같이 전송하는 방법을 선택했습니다. 이 해더는 이 글에 나와있는 것처럼 이 해더의 이름은 아마도 AWS API Gateway에서 사용되어서 유행이 되었다고 합니다.

 

3. 방문 예약 서비스에 적용하기

  방문 예약 서비스와 단축 URL 서비는 별도의 서비스 입니다. 따라서 방문 예약 서비스에서 단축 URL 서비스를 호출하게 된다면,

방문 예약 서비스임을 인증할 API Key가 필요하고, 이 키는 단축 URL 서비스 내부에서 인증되는 형식이어야 합니다.

 현재 URL 서비스에서는 별도의 인증로직이 없고, 이 로직을 만드려면 공수가 많이 들어가기 때문에, 자체적으로 키를 등록하고, 이 키를 방문 예약 서비스와 공유해서 사용하고 있습니다.

 

 

'42' 카테고리의 다른 글

QueryDSL 도입기  (0) 2021.11.09
Java Out Of Memory Error: Java heap space  (0) 2021.09.19
URL Shortener 개발기  (0) 2021.08.06