서버 측 요청 위조
서버 측 요청 위조 취약점은 사용자가 애플리케이션이 공격자가 지정한 도메인에 HTTP 요청을 하도록 만들 수 있을 때 발생합니다. 애플리케이션이 사설/내부 네트워크에 액세스할 수 있는 경우 공격자는 애플리케이션이 내부 서버에 요청을 하도록 만들 수도 있습니다.
실제로 어떻게 작동하는지 더 잘 이해할 수 있도록 몇 가지 예를 통해 자세히 살펴보겠습니다.
페이지 미리보기나 내보내기 등의 용도로 사용자로부터 URL을 받아 사용자가 제공한 URL의 사진을 생성하는 API를 생각해 보세요.
ts
let url = request.params.url;
let response = http.get(url);
let render = response.render();
return render.export();
URL 매개변수는 사용자가 제어하기 때문에 공격자가 원하는 모든 URL에 간단히 액세스할 수 있습니다. 경우에 따라 URL에 액세스하는 데 사용되는 라이브러리에 따라 'file://' 스키마를 사용하는 로컬 파일일 수도 있습니다.
AWS에서 호스팅되는 경우 SSRF 취약점을 악용하는 일반적인 방법은 AWS API의 자격 증명을 포함할 수 있는 AWS 메타데이터 API에 액세스하는 데 사용하는 것입니다. 이렇게 하면 계정 내의 다른 AWS 리소스에 대한 추가 액세스로 이어질 수 있으며, 이는 상상할 수 있듯이 바람직하지 않습니다.
완화
SSRF 취약점을 완화하는 것은 때때로 매우 까다로울 수 있으며, 문제의 코드가 달성하려는 목표에 따라 크게 달라집니다. 요구 사항에 따라 적용할 수 있는 완화 방법은 다양합니다.
사용자가 결정한 URL을 피하세요.
경우에 따라 사용자가 임의의 URL을 제공하지 않는 방식으로 기능을 구현할 수 있을 수도 있습니다. 이것이 가능하다면 SSRF의 위험을 완화하는 가장 효과적인 방법입니다.
기능 최소화
PDF 내보내기 기능을 구현하는 경우, 헤드리스 브라우저를 사용하여 페이지의 스크린샷을 찍는 경우가 있습니다. 하지만 브라우저의 복잡성과 브라우저에 노출되는 수많은 기능과 공격 표면을 고려할 때 이는 항상 바람직하지 않습니다.
당면한 작업에 적합한 도구를 사용하는 것이 중요합니다. 경우에 따라서는 간단한 HTTP 클라이언트로도 충분할 수 있습니다. 기능 및 사용 가능한 공격 표면/벡터를 최소화하기 위해 항상 할 수 있는 일이 있습니다. 예를 들어, HTTP 클라이언트의 경우:
- 다음 리디렉션을 비활성화합니다.
- HTTPS 이외의 모든 체계를 비활성화합니다.
몇 가지 함정이 있습니다.
리디렉션 및 아이프레임
비공개 리소스(IP 주소 또는 내부 호스트 이름)에서 SSRF로부터 보호하는 일반적인 방법은 사용자가 제공한 URL을 파싱하고 '거부 목록'을 사용하여 민감한 리소스에 대한 액세스를 차단하는 것입니다.
이 방법은 클라이언트가 HTTP 리디렉션, HTML/JavaScript 리디렉션을 따르거나 iframe과 같은 복잡한 요소를 렌더링할 수 있는 시나리오에서는 우회할 수 있으므로 대부분의 경우 효과적이지 않다는 점에 유의할 필요가 있습니다.
공격자는 민감한 리소스로 리디렉션되는 페이지를 호스팅하는 취약한 애플리케이션에 HTTP 301/302, HTML 메타 리디렉션, 로드 시 자바스크립트로 현재 URL을 설정하거나 내부 리소스를 보여주는 iframe을 임베드하는 방식으로 URL을 제공할 수 있습니다. 이렇게 하면 원본 URL의 유효성을 검사하려는 시도를 효과적으로 우회할 수 있습니다.
DNS 리바인딩
다른 "유형"의 리디렉션도 DNS를 통해 수행할 수 있습니다. SSRF 공격을 방지하는 일반적인 방법 중 하나는 다음을 수행하는 것입니다:
- 제공된 URL 구문 분석
- 호스트 이름을 가져와서 DNS 조회를 수행합니다.
- URL이 내부/비공개 IP로 확인되면 URL을 거부하고, 공개 IP인 경우 URL을 수락합니다.
이 방법은 "DNS 리바인딩"에 취약하기 때문에 실제로 효과적이지 않습니다. DNS 리바인딩은 원격 호스트에 의해 TCP 연결이 닫힐 때 대부분의 네트워크 스택(예: Linux 및 Windows)의 표준 동작으로 인해 작동합니다.
원격 호스트가 연결을 강제로 닫으면 다른 DNS 쿼리를 수행하여 IP 주소를 다시 확인한 후 다시 연결을 시도합니다.
이를 통해 공격자는 다음을 수행할 수 있습니다:
- TTL(Time-to-live)이 매우 짧은 개방형 HTTP 포트가 있는 공개 IP 주소로 `rebinding.attacker.com`에 대한 DNS 항목을 만듭니다.
- 취약한 애플리케이션에 URL(예: https://rebinding.attacker.com/)을 전송합니다. 확인된 IP가 비공개 IP가 아닌지 확인한 후 안전하다고 판단하여 요청된 작업을 진행합니다.
- HTTP 연결이 완료되면 "rebinding.attacker.com"의 DNS 항목이 내부 IP 주소로 변경됩니다.
- HTTP 연결이 강제로 닫힙니다.
- 이제 애플리케이션이 내부 IP 주소를 가리키는 "rebinding.attacker.com"의 IP 주소를 다시 확인합니다.
- IP 확인 보호가 이미 발생했고 DNS 항목의 재확인 및 재연결이 모두 커널에서 발생하기 때문에 애플리케이션은 이제 IP가 변경되었다는 사실을 인식하지 못합니다.
이렇게 하면 비공개 IP 주소로 확인되는 URL 제공에 대한 보호 기능을 효과적으로 우회할 수 있습니다.
IPv4와 IPv6
'거부 목록'을 우회하는 또 다른 일반적인 방법은 IPv6를 사용하는 것입니다. 모든 IPv4 주소는 IPv6 주소로 표현할 수 있기 때문에 액세스하려는 IPv4 주소에 매핑되는 IPv6 주소를 사용하여 거부 목록을 우회할 수 있는 경우가 많습니다.