Bulletproof API 디자인: 18가지 규칙
Grace Collins
Solutions Engineer · Leapcell

1. 서명
API 인터페이스의 데이터가 변조되는 것을 방지하기 위해 API 인터페이스에 대한 서명을 구현해야 하는 경우가 많습니다.
API 요청자는 요청 파라미터, 타임스탬프 및 비밀 키를 문자열로 연결한 다음 MD5 또는 기타 해시 알고리즘을 사용하여 서명(sign
)을 생성합니다.
이 sign
은 요청 파라미터 또는 헤더에 포함되어 API로 전송됩니다.
API 게이트웨이 서비스 측에서 게이트웨이는 sign
값을 검색한 다음 동일한 요청 파라미터, 타임스탬프 및 비밀 키를 사용하여 동일한 MD5 알고리즘으로 다른 sign
을 생성합니다. 그런 다음 두 sign
값을 비교합니다.
- 두
sign
값이 일치하면 요청이 유효한 것으로 간주되고 API 게이트웨이 서비스는 해당 요청을 적절한 비즈니스 시스템으로 전달합니다. - 두
sign
값이 일치하지 않으면 API 게이트웨이 서비스는 서명 오류를 반환합니다.
서명에 타임스탬프를 포함하는 이유는 무엇입니까?
보안을 강화하고 동일한 요청이 반복적으로 사용되는 것을 방지하기 위해 타임스탬프가 서명에 포함됩니다. 이렇게 하면 비밀 키가 해킹될 가능성도 줄어듭니다. 각 요청에는 15분과 같이 합리적인 만료 시간이 있어야 합니다.
따라서 요청은 15분 동안 유효합니다. 15분을 초과하면 API 게이트웨이 서비스는 요청이 만료되었음을 나타내는 오류를 반환합니다.
현재 서명에 사용되는 비밀 키를 생성하는 방법에는 두 가지가 있습니다.
- 고정 개인 키(
privateKey
): 양측은 고정 값을 비밀 키로 합의합니다. - AK/SK 키 쌍: API 제공자는
AK/SK
키 쌍을 할당합니다.SK
는 서명에서 비밀 키로 사용되고AK
는 요청 헤더에accessKey
로 전송됩니다. API 제공자는AK
를 사용하여SK
를 검색하고 유효성 검사를 위해 새sign
을 생성합니다.
2. 암호화
경우에 따라 API 인터페이스는 사용자 로그인 비밀번호, 은행 카드 번호 및 이체 금액과 같이 매우 민감한 데이터를 전송합니다. 공용 인터넷을 통해 이러한 파라미터를 일반 텍스트로 노출하는 것은 매우 위험합니다.
이러한 위험을 완화하려면 암호화를 구현해야 합니다.
예를 들어 사용자 등록 인터페이스에서 사용자가 사용자 이름과 비밀번호를 입력한 후 비밀번호를 암호화해야 합니다.
일반적인 접근 방식은 AES 대칭 암호화를 사용하는 것입니다.
- 프런트 엔드에서 사용자의 비밀번호는 공개 키를 사용하여 암호화됩니다.
- 그런 다음 등록 API는 비밀 키를 사용하여 비밀번호를 해독하고 필요한 비즈니스 유효성 검사를 수행한 다음 데이터베이스에 저장하기 전에 다른 암호화 방법으로 다시 암호화합니다.
3. IP 화이트리스트
API 보안을 더욱 강화하기 위해 IP 화이트리스트를 구현할 수 있습니다. 서명 또는 암호화 메커니즘이 손상되더라도 공격자는 여전히 승인된 IP 주소에서 API를 요청해야 합니다.
해결 방법은 IP 주소를 기반으로 API 요청을 제한하여 화이트리스트에 등록된 IP의 요청만 허용하는 것입니다.
- API 요청이 화이트리스트에 등록된 IP에서 시작되면 정상적으로 처리됩니다.
- 요청이 화이트리스트에 등록되지 않은 IP에서 온 경우 즉시 액세스가 거부됩니다.
IP 화이트리스트는 API 게이트웨이 수준에서 적용할 수 있습니다.
그러나 회사 내의 내부 애플리케이션 서버도 손상되어 공격자가 네트워크 내에서 API 요청을 보낼 수 있습니다.
이를 방지하기 위해 추가 보호를 위해 ModSecurity와 같은 웹 방화벽을 배포해야 합니다.
4. 속도 제한
타사 플랫폼이 API를 호출할 때 요청 빈도를 제어할 수 없습니다.
타사가 갑자기 대량의 요청을 동시에 보내면 API 서비스가 과부하되어 다운될 수 있습니다.
따라서 속도 제한을 구현해야 합니다.
일반적인 속도 제한 전략은 세 가지가 있습니다.
-
IP당 요청 제한 예: 단일 IP는 분당 최대 10,000개의 요청을 할 수 있습니다.
-
API 엔드포인트당 요청 제한 예: 단일 IP는 특정 API 엔드포인트에 분당 최대 2,000개의 요청을 할 수 있습니다.
-
사용자(AK/SK)당 요청 제한 예: 단일 AK/SK 사용자는 분당 최대 10,000개의 API 요청을 할 수 있습니다.
실제 애플리케이션에서 속도 제한은 Nginx, Redis 또는 API 게이트웨이를 사용하여 구현할 수 있습니다.
5. 파라미터 유효성 검사
API 인터페이스는 다음과 같은 파라미터 유효성 검사를 적용해야 합니다.
- 필수 필드가 비어 있는지 확인합니다.
- 필드 유형을 확인합니다.
- 필드 길이의 유효성을 검사합니다.
- 열거된 값이 올바른지 확인합니다.
이렇게 하면 불필요한 처리를 방지하여 프로세스 초기에 잘못된 요청을 필터링하는 데 도움이 됩니다.
예를 들어 요청이 허용된 최대 길이를 초과하는 필드에 데이터를 삽입하려고 하면 데이터베이스에서 오류가 발생합니다. 그러나 이러한 유효성 검사는 시스템 리소스를 절약하기 위해 데이터베이스 작업을 전에 처리해야 합니다.
유효성 검사 함정의 예:
- 잘못된 금액 값: 필드가 양수를 저장해야 하지만 음수 값이 허용되는 경우 예기치 않은 손실이 발생할 수 있습니다.
- 잘못된 상태 값: 시스템에서 상태 필드의 유효성을 검사하지 않고 알 수 없는 값을 받으면 데이터베이스가 손상될 수 있습니다.
일반적인 유효성 검사 프레임워크
Java에서 가장 일반적으로 사용되는 유효성 검사 프레임워크는 다음과 같은 주석을 포함하는 Hibernate Validator입니다.
@Null
@NotEmpty
@Size
@Max
@Min
이러한 주석을 사용하면 데이터 유효성 검사가 간단해집니다.
날짜 필드 및 열거형 필드의 경우 유효성 검사를 위해 사용자 지정 주석이 필요할 수 있습니다.
6. 통합 응답 형식
서로 다른 응답에 일관성 없는 JSON 형식이 있는 API를 접했습니다. 예:
정상 응답:
{ "code": 0, "message": null, "data": [{ "id": 123, "name": "abc" }] }
서명 오류 응답:
{ "code": 1001, "message": "Signature error", "data": null }
권한 거부 응답:
{ "rt": 10, "errorMgt": "No permission", "result": null }
왜 문제가 됩니까?
API가 다른 형식으로 응답을 반환하면 통합자에게 불필요한 혼란이 발생합니다.
이 문제는 종종 다음과 같은 경우에 발생합니다.
- API 게이트웨이에 응답 형식이 하나 있습니다.
- 비즈니스 시스템에 다른 응답 형식이 있습니다.
API 게이트웨이 오류가 발생하면 한 형식이 반환됩니다. 비즈니스 시스템 오류가 발생하면 다른 형식이 반환됩니다.
해결 방법: 응답 구조 표준화
API 게이트웨이는 통합 응답 형식을 적용해야 합니다.
비즈니스 시스템이 오류 메시지가 포함된 RuntimeException을 throw하면 API 게이트웨이가 이 예외를 캐치하여 표준화된 형식으로 반환해야 합니다.
7. 통합 예외 처리
API 인터페이스는 일관된 예외 처리를 구현해야 합니다.
데이터베이스 문제(예: 누락된 테이블 또는 SQL 구문 오류)로 인해 API 요청이 실패하고 응답이 원시 SQL 오류를 직접 반환하는 상황을 겪어본 적이 있습니까?
잘못 설계된 일부 API는 응답에 예외 스택 추적, 데이터베이스 세부 정보, 오류 코드 및 줄 번호까지 노출할 수 있습니다.
이것은 심각한 보안 위험입니다.
악의적인 행위자는 이 정보를 악용하여 SQL 삽입 공격을 수행하거나 데이터베이스를 직접 유출하여 시스템 침해로 이어질 수 있습니다.
해결 방법: 중요한 오류 세부 정보 마스크
원시 오류 메시지를 노출하는 대신 모든 API 예외를 다음과 같은 표준 오류 응답으로 변환해야 합니다.
{ "code": 500, "message": "Internal Server Error", "data": null }
code
필드는500
입니다(서버 오류에 대한 표준 HTTP 오류 코드).message
필드는 내부 시스템 세부 정보를 노출하지 않고 일반 오류 메시지입니다.
디버깅을 위한 내부 로깅
문제를 디버깅하려면 내부 로그에 다음이 계속 기록되어야 합니다.
- 전체 예외 스택 추적
- 데이터베이스 오류 세부 정보
- 정확한 오류 줄 번호
이렇게 하면 내부 팀이 외부 사용자에게 중요한 데이터를 노출하지 않고 문제를 진단하는 데 필요한 정보를 얻을 수 있습니다.
게이트웨이 수준 예외 인터셉션
예외 처리는 API 게이트웨이 수준에서 적용하여 모든 오류 응답이 일관되고 정리된 형식을 따르도록 할 수 있습니다.
8. 요청 로깅
요청 로그는 특히 타사 플랫폼의 경우 API 호출 문제를 진단할 때 매우 중요합니다.
추적 가능성을 보장하려면 다음 API 요청 세부 정보를 기록하십시오.
- 요청 URL
- 요청 파라미터
- 요청 헤더
- HTTP 메서드
- 응답 데이터
- 응답 시간
요청 추적을 위해 traceId
사용
**traceId
**는 로그에 포함되어 특정 요청에 대한 모든 관련 로그를 함께 연결할 수 있어야 합니다. 이렇게 하면 문제를 해결할 때 관련 없는 로그를 필터링하는 데 도움이 됩니다.
타사가 로그에 액세스할 수 있도록 하기
경우에 따라 타사 플랫폼도 요청 로그에 액세스해야 할 수 있습니다.
이를 용이하게 하려면 다음을 수행하십시오.
- MongoDB 또는 Elasticsearch와 같은 데이터베이스에 로그를 저장합니다.
- 타사 사용자가 로그를 검색하고 볼 수 있는 UI 대시보드를 개발합니다.
이렇게 하면 셀프 서비스 디버깅이 가능하므로 외부 사용자가 사소한 문제에 대해 지원팀에 문의할 필요가 줄어듭니다.
9. 멱등성 설계
타사 플랫폼은 시스템에 버그가 있거나 API 응답이 지연되거나 실패할 때 재시도 메커니즘으로 인해 매우 짧은 시간에 중복된 API 요청을 보낼 수 있습니다.
API가 멱등성을 처리하지 않으면 중복된 요청으로 인해 중복된 레코드가 생겨 데이터 불일치가 발생할 수 있습니다.
해결 방법: 중복된 요청으로 인해 중복된 레코드가 생성되지 않도록 합니다.
동일한 API 요청이 짧은 시간 내에 여러 번 수신되는 경우:
- 첫 번째 요청은 정상적으로 처리되고 데이터가 삽입됩니다.
- 이후의 동일한 요청은 새 데이터를 삽입하지 않지만 여전히 성공 응답을 반환합니다.
구현 접근 방식
-
데이터베이스의 고유 제약 조건
- 중복된 항목을 방지하기 위해 요청 파라미터에 고유 인덱스를 사용합니다.
-
Redis를 사용하여 중복 제거
- 요청 파라미터와 함께 Redis에 **
requestId
**를 저장합니다. - 동일한
requestId
가 다시 수신되면 요청을 거부합니다.
- 요청 파라미터와 함께 Redis에 **
10. 배치 API의 레코드 수 제한
배치 처리 API의 경우 요청당 레코드 수를 제한하는 것이 매우 중요합니다.
그 이유는 무엇일까요?
- 요청당 너무 많은 레코드를 허용하면 API 시간 초과 및 불안정성이 발생할 수 있습니다.
- 페이로드가 클수록 서버 로드가 증가하고 전반적인 API 성능이 저하됩니다.
권장 제한
- 단일 API 요청은 최대 500개의 레코드를 허용해야 합니다.
- 500개 이상의 레코드가 전송되면 API는 오류를 반환해야 합니다.
이 제한은 구성 가능해야 하고 라이브로 전환하기 전에 타사 사용자와 합의해야 합니다.
대규모 쿼리에 대한 페이지 매김
API가 대규모 데이터 세트를 반환해야 하는 경우 한 번의 요청으로 모든 데이터를 반환하는 대신 페이지 매김을 구현합니다.
11. 로드 테스트
API를 시작하기 전에 QPS(초당 쿼리 수) 제한을 이해하려면 로드 테스트가 필수적입니다.
속도 제한이 적용된 경우에도 API가 예상되는 로드를 실제로 처리할 수 있는지 확인해야 합니다.
예시 시나리오
- API 속도 제한은 초당 50개의 요청으로 설정됩니다.
- 그러나 실제 서버 용량은 초당 30개의 요청만 처리할 수 있습니다.
- 즉, 속도 제한이 적용되어도 API가 여전히 충돌할 수 있습니다.
로드 테스트 도구
- JMeter
- Apache Bench(
ab
)
스트레스 테스트를 실행하면 안정적인 성능을 유지하는 데 얼마나 많은 서버 노드가 필요한지 확인할 수 있습니다.
12. 비동기 처리
대부분의 API는 동기식이며 요청이 즉시 처리되고 응답이 실시간으로 반환됨을 의미합니다.
그러나 일부 복잡한 작업, 특히 배치 처리는 실행하는 데 너무 오래 걸릴 수 있습니다.
해결 방법: 오래 실행되는 작업을 비동기 처리로 변환합니다.
-
MQ(메시지 큐) 메시지 보내기
- API는 작업을 대기열에 넣은 후 성공을 즉시 반환합니다.
- 별도의 메시지 소비자가 작업을 비동기적으로 처리합니다.
-
타사가 처리 결과를 확인할 수 있도록 하기
- 콜백 접근 방식: 처리가 완료되면 타사 API에 알립니다(결제 API에서 일반적).
- 폴링 접근 방식: 타사는 진행 상황을 추적하기 위해 상태 확인 API를 반복적으로 호출합니다.
13. 데이터 마스킹(데이터 삭제)
일부 API 응답에는 다음과 같은 민감한 사용자 데이터가 포함되어 있습니다.
- 전화 번호
- 은행 카드 번호
이 정보가 마스킹 없이 노출되면 데이터 유출 위험이 증가합니다.
해결 방법: 데이터 마스킹 적용
예를 들어 은행 카드 번호를 마스킹합니다.
- 원본:
5196123456781234
- 마스크 처리됨:
5196****1234
데이터가 유출되더라도 부분적으로 보호된 상태로 유지되어 보안 위험이 줄어듭니다.
14. 포괄적인 API 문서
문서화가 잘된 API는 통합 노력을 줄이고 오해를 최소화합니다.
API 문서에는 다음이 포함되어야 합니다.
- API URL
- HTTP 메서드(예: GET, POST)
- 요청 파라미터 및 필드 설명
- 응답 형식 및 필드 설명
- 오류 코드 및 메시지
- 암호화 및 서명 예제
- 예제 요청
- 추가 요구 사항(예: IP 화이트리스트)
명명 규칙 표준화
일관성을 유지하려면 다음을 수행하십시오.
- 필드 이름에 camelCase를 사용합니다.
- 필드 유형 및 길이 표준화(예:
id
를Long
으로,status
를int
로). - 통일된 시간 형식을 정의합니다(예:
yyyy-MM-dd HH:mm:ss
).
문서에는 AK/SK 키 사용법 및 API 도메인 이름도 지정해야 합니다.
15. 요청 메서드
API는 다음을 포함하여 다양한 요청 메서드를 지원합니다.
- GET
- POST
- PUT
- DELETE
올바른 방법 선택
- GET: 읽기 전용 요청에 적합합니다(파라미터를 보낼 필요가 없는 경우).
- POST: 파라미터가 필요한 경우 권장됩니다(문제 발생 가능성이 적음).
GET 대신 POST를 사용하는 이유는 무엇입니까?
- POST를 사용하면 파라미터 확장이 더 쉬워집니다
- Feign API 호출에서 새 파라미터를 추가해도 기존 코드를 수정할 필요가 없습니다.
- GET에는 URL 길이 제한이 있습니다
- 최대 5000자, POST는 제한 없음.
16. 요청 헤더
인증 토큰 또는 traceId와 같은 특정 파라미터는 쿼리 파라미터 대신 요청 헤더를 통해 전송해야 합니다.
예를 들면 다음과 같습니다.
- 모든 API 요청에서 URL 파라미터로 traceId를 추가하는 대신
- 클라이언트는 요청 헤더에 traceId를 보내야 합니다.
그러면 서버는 인터셉터를 사용하여 traceId를 추출할 수 있습니다.
17. 배치 처리
API를 설계할 때 데이터 쿼리, 추가, 업데이트 또는 삭제 여부에 관계없이 배치 처리를 항상 고려해야 합니다.
배치 처리가 중요한 이유는 무엇입니까?
많은 시나리오에서 여러 레코드를 한 번에 쿼리해야 합니다. 예를 들어 주문 세부 정보 검색:
- API가 한 번에 하나의 주문만 가져올 수 있는 경우 각 주문에 대해 별도의 API 호출이 필요합니다.
- API가 배치 검색을 지원하는 경우 단일 요청으로 여러 주문을 검색하여 효율성을 높일 수 있습니다.
마찬가지로 데이터를 추가할 때:
- API가 요청당 하나의 레코드만 추가할 수 있는 경우 배치 작업에서 1,000개의 레코드를 삽입해야 하는 경우 1,000개의 별도 API 호출이 필요합니다.
- 대신 배치 삽입 API를 사용하면 하나의 요청으로 모든 1,000개의 레코드를 제출하여 오버헤드를 줄일 수 있습니다.
설계 권장 사항:
- 가능하면 API는 단일 레코드만 처리하는 대신 배치 작업을 지원해야 합니다.
- 이렇게 하면 API가 다양한 비즈니스 요구 사항에 대해 더 일반적이고 확장 가능해집니다.
18. 단일 책임 원칙
일부 API 설계는 지나치게 복잡하여 단일 요청에서 수많은 조건을 지원합니다. 결과적으로:
- 서비스 계층(
Service
클래스)에는 과도한if...else
문이 포함되어 있습니다. - 응답 모델에는 가능한 모든 필드가 포함되어 속성의 수가 압도적으로 많아집니다.
지나치게 복잡한 API의 문제점:
- 유지 관리하기 어려움: 1년 후에는 원래 개발자조차 특정 시나리오에 필요한 필드를 기억하기 어려울 수 있습니다.
- 호환성이 손상될 위험이 큼: 시나리오 A에 대한 논리를 수정하면 부주의하게 시나리오 B에 영향을 미칠 수 있습니다.
해결 방법: 단일 책임 원칙을 따릅니다.
만능 API 대신 API를 더 작고 시나리오별 엔드포인트로 분할합니다.
예: 주문 배치 API의 경우 두 개의 플랫폼(웹 및 모바일)과 두 개의 주문 방법(표준 및 빠른)이 있습니다.
하나의 API로 모든 것을 처리하는 대신 분리합니다.
- 웹 플랫폼 API
/web/v1/order/create /web/v1/order/fastCreate
- 모바일 플랫폼 API
/mobile/v1/order/create /mobile/v1/order/fastCreate
결과적으로 네 개의 고유한 API가 만들어지며 각 API는 특정 사용 사례에 전념합니다. 장점:
- 비즈니스 논리는 명확하게 유지됩니다.
- API는 유지 관리하기 더 쉽습니다.
- 변경할 때 의도하지 않은 부작용이 발생할 위험이 적습니다.
결론
이러한 모범 사례를 따르면 API 인터페이스가 더 안전하고 확장 가능하며 유지 관리 가능해집니다. 이러한 원칙은 다음을 돕습니다.
- 보안 취약성 방지(예: 무단 액세스, SQL 삽입).
- 성능 최적화(예: 속도 제한, 배치 처리).
- 개발자 환경 개선(예: 표준화된 응답, 명확한 API 문서).
내부 시스템용 API를 설계하든 타사 통합을 위한 API를 설계하든 이러한 모범 사례를 채택하면 더욱 강력하고 미래 지향적인 아키텍처를 보장할 수 있습니다.
Leapcell은 백엔드 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 지불하십시오. 요청도 없고 요금도 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불하십시오.
- 예: $25는 평균 응답 시간이 60ms인 694만 개의 요청을 지원합니다.
간소화된 개발자 경험
- 손쉬운 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
간편한 확장성 및 고성능
- 고도의 동시성을 쉽게 처리하기 위한 자동 확장.
- 운영 오버헤드가 없으므로 구축에만 집중하십시오.
설명서에서 자세히 알아보십시오!
X에서 우리를 팔로우하십시오: @LeapcellHQ