[javascript] 자체 속도 제한 API를 Dogfooding

개요 :

우리 회사는 요금 제한 API를 개발했습니다. 우리의 목표는 두 가지입니다.

  • A : 제품을 중심으로 강력한 개발자 생태계를 만드십시오.
  • B : 자체 애플리케이션을 구동하는 데 API를 사용하여 API의 힘을 보여줍니다.

설명 : 왜 속도 제한이 있습니까?

API를 제품에 추가하여 판매하기 때문에 API 등급을 제한합니다. API에 대한 익명 액세스는 시간당 API 호출에 대한 임계 값이 매우 낮은 반면, 유료 고객은 시간당 1000 개 이상의 호출이 허용됩니다.

문제 :

속도 제한 API는 개발자 생태계에 적합하지만 dogfood를 위해 동일한 속도 제한으로 제한하는 것을 허용 할 수 없습니다. API의 프런트 엔드는 모두 JavaScript이며 API에 대한 직접 Ajax 호출을 수행합니다.

그래서 질문은 :

속도 제한을 제거하는 과정에서 쉽게 스푸핑 할 수없는 속도 제한을 제거 할 수 있도록 API를 어떻게 보호합니까?

탐색 된 솔루션 (및 작동하지 않는 이유)

  1. 호스트 헤더에 대해 리퍼러를 확인하십시오. – 리퍼러 가 쉽게 위조 되기 때문에 결함 이 있습니다.

  2. 사용 HMAC를 다음 서버에 요청을 확인, 요청 및 공유 비밀 기반으로 서명을 만들 수 있습니다. – 프론트 엔드 JavaScript를 조사하여 비밀과 알고리즘을 쉽게 결정할 수 있기 때문에 결함이 있습니다.

  3. 요청 프록시 및 프록시에서 요청 서명- 프록시 자체가 API를 노출하므로 여전히 결함이 있습니다.

질문:

대체 솔루션을 제시하기 위해 Stack Overflow의 뛰어난 마음을 찾고 있습니다. 이 문제를 어떻게 해결 하시겠습니까?



답변

자신의 JavaScript 클라이언트가 API에 직접 액세스하기 때문에 누구나 동일한 API 키를 사용하는 것을 포함하여 수행중인 작업을보고 모방 할 수 있습니다. 코드를 난독 화하거나 다양한 장애물을 두는 등 더 어렵게 만들 수 있지만, 제한하려는 사람과 기본적으로 동일한 액세스 권한이 있습니다. 권한의 차이를 만드는 대신 비공식 클라이언트가 해당 범위의 모든 액세스를 사용하는 것이 전적으로 괜찮은 시스템을 구성해야하지만 시스템은 모든 클라이언트에서 공식적으로 사용되는 방식으로 배열됩니다. 더 크다.

이는 전체 애플리케이션에 대해 하나의 토큰이 아닌 사용자 별 액세스 토큰으로 수행되는 경우가 많습니다. 각 토큰의 한도는 API의 일반적인 사용에 충분해야하지만이를 악용하려는 누군가에게는 제한적이어야합니다. 예를 들어 분당 100 통의 통화는 일반적인 탐색을 지원하기에 충분할 수 있지만 스크랩하고 싶다면 해당 예산으로 효과적으로 할 수 없습니다.

항상 군비 경쟁이있을 것입니다. 봇 사용자 계정을 많이 만들어 한계를 극복 할 수 있습니다. 그러나 실제 사람에게 약간의 비용을 들여 가입 절차에 보안 문자를 추가하면 꽤 해결 된 문제입니다. 이러한 시나리오에 들어가면 모든 것이 편리함과 제한 사이의 절충점 일뿐입니다. 완전히 방탄을 찾을 수는 없으므로 충분히 좋은 것을 만드는 데 집중하고 누군가가 당신을 착취하여 구멍이 어디에 있는지 알 때까지 기다리십시오.


답변

이것이 문제를 일으키는 경우 개발자의 추정 생태계에 문제가 발생할 것입니다 (예 : 대체 UI를 개발하려고 할 때). 정말로 자신의 개 사료를 먹고 있다면 API (및 속도 제한)가 애플리케이션에 적합하도록 만드십시오. 몇 가지 제안이 있습니다 :

  • IP 주소로 속도 제한을하지 마십시오. 오히려 사용자와 관련된 항목 (예 : 사용자 ID)에 의한 속도 제한. 인증 단계에서 속도 제한을 적용합니다.

  • 사용자가 지속적으로 호출 할 필요가 없도록 API를 설계합니다 (예 : 매번 항목을 하나씩 반환하는 반복 호출 대신 많은 결과를 반환하는 목록 호출 제공).

  • 개발자 에코 시스템이 가질 것으로 기대하는 것과 동일한 제약 조건으로 웹 앱을 디자인하십시오. 즉, 합리적인 제한 속도 내에서 디자인 할 수 있는지 확인하십시오.

  • 백엔드가 확장 가능하도록 (수평 적으로 가급적이면) UI에 문제를 일으킬 정도로 낮은 수준에서 제한을 부과 할 필요가 없습니다.

  • 스로틀 링이 버스트에 대처할 수있을뿐만 아니라 장기간 남용을 제한 할 수 있는지 확인하십시오.

  • 스로틀 링이 제거하려는 남용에 맞는 적절한 조치를 수행하는지 확인하십시오. 예를 들어, 연결을 거부하기보다는 가벼운 학대자를 대기 시키거나 지연시키는 것이 좋습니다. 대부분의 웹 프런트 엔드는 한 번에 4 개의 동시 연결 만 엽니 다. 5 분의 1을 열려는 시도를 지연하면 웹 클라이언트와 동시에 CLI를 사용하는 경우에만 해당됩니다 (2 개의 웹 클라이언트가 아님). 실패하지 않고 공백없이 n 번째 API 호출을 지연하면 최종 사용자는 중단되지 않고 속도가 느려지는 것을 보게됩니다. 이것을 한 번에 N 개의 API 호출 만 큐잉하는 것과 결합하면 많은 수의 API 호출을 병렬 처리하는 사람들 만 공격 할 수 있습니다. 이는 아마도 원하는 동작이 아닐 것입니다. 예를 들어 100 개의 동시 API 호출이 있으면 일반적으로 한 시간 동안의 간격이 멀습니다. 한 시간 동안 100 번의 순차 API 호출보다 더 나쁩니다.

이것이 귀하의 질문에 대한 답변이 아닙니까? 글쎄요, 정말로 당신이 요구 하는 것을 해야 한다면 인증 단계에서 속도 제한을하고 사용자가 속한 그룹에 따라 다른 속도 제한을 적용하십시오. 개발자 및 QA 팀에서 사용하는 한 세트의 자격 증명을 사용하는 경우 더 높은 속도 제한이 적용됩니다. 그러나 이것이 필연적으로 개발자 및 QA 팀이 보지 못하는 문제를보고 생태계로 이끄는 이유를 즉시 알 수 있습니다.


답변

제품을 구입하십시오. 자신의 유료 고객이 되십시오.

“우리 API에 대한 익명 액세스는 시간당 API 호출에 대한 임계 값이 매우 낮은 반면, 유료 고객은 시간당 1000 호출 이상을 허용합니다.”

이것은 또한 고객의 관점에서 시스템을 테스트하는 데 도움이됩니다.


답변

불행히도 이것에 대한 완벽한 해결책은 없습니다.

일반적인 접근 방식은 일반적으로 스푸핑 가능한클라이언트가 자신을 식별하는 방법 (예 : 식별자, 버전 및 API 키), 클라이언트가 액세스를 제한하는 데 사용할 수있는 자신에 대한 정보를 등록하는 방법 (예 : 클라이언트는 지정된 IP 주소 범위의 서버입니다. 따라서 해당 범위의 호출자 만 허용합니다. 예를 들어 클라이언트는 JavaScript이지만 특정 범주의 브라우저에만 전달되므로 특정 사용자 에이전트 문자열 등을 지정하는 HTTP 요청에 대한 액세스 만 허용 한 다음 머신 러닝 / 패턴을 사용합니다. 스푸핑 된 클라이언트 일 가능성이있는 비정상적인 사용을 감지 한 다음 이러한 스푸핑 된 클라이언트의 트래픽을 거부하는 인식 (또는 이러한 사용이 실제로 합법적 인 클라이언트에서 오는 것이 아님을 클라이언트에 확인하고 스푸핑 가능한 자격 증명을 교체 한 다음 이전 트래픽을 사용하여 추가 트래픽을 허용하지 않음) 스푸핑 된 자격 증명).

여러 계층의 키를 사용하여 스푸핑을 약간 더 어렵게 만들 수 있습니다. 예를 들어 클라이언트 (예 : 사용자 에이전트)에 대한 정보를 기록하는 API 호출을 만들기 위해 서버에있는 (제한된 IP 주소 범위에서만 사용할 수있는) 수명이 긴 자격 증명을 제공합니다. 클라이언트 측 API 요청을 위해 클라이언트에서 사용하기 위해 JavaScript로 신디케이트 된 수명이 더 짧은 클라이언트 측 키를 반환합니다. 이것도 불완전하지만 (스푸 퍼가 동일한 서버 호출을 발행하여 자격 증명을 얻을 수 있음), 반환 된 API 키가 난독 화 된 (그리고 자주 변경되는) JavaScript 또는 HTML에 포함되어 있으면 더 어려워집니다 (어려움을 유발할 수 있음). 응답에서 안정적으로 추출). 또한 스푸핑을보다 쉽게 ​​탐지 할 수있는 방법을 제공합니다. 클라이언트 측 키는 이제 특정 클라이언트에 연결됩니다 (예 :


답변

문제의 앱이 공개적으로 열려 있어야한다고 가정하면 선택의 여지가별로 없습니다.

API의 힘을 보여주는 다른 방법을 선택하세요. 예를 들어 이러한 앱을 작성하고 소스를 공유하지만 실제로 해당 코드를 실행하지는 마십시오. 그러나 누구나 배포하고 작동하는 것을 볼 수 있도록 문서화가 잘되어 있는지 확인하십시오 (조절에 따라 다름).

실행하는 앱은 클라이언트 측 API 요청을 방지하고 서버에서 더 많이 렌더링되도록 리팩터링해야합니다. API를 dogfood 할 수는 있지만 명백한 방법은 아닙니다. 서버 측에서 제한없는 API에 대한 보안 요청을 만드세요.

앱이 작동하도록 속도 제한조정 하고 부하를 처리하기위한 성능 최적화에 투자합니다.

그리고 네, 우선 핵심 API를 스로틀 프리로 유지하고 사설 네트워크 내에 보관하십시오. 공개적으로 액세스 할 수있는 별도의 레이어에서 제한합니다.


답변

UI 및 스로틀 프리 API의 별도 인스턴스를 설정 한 다음 조직에서 오는 IP 주소에 대한 액세스를 제한 할 수 있습니까?

예를 들어 회사 방화벽 뒤에 모든 것을 배포하고 인스턴스간에 데이터를 공유해야하는 경우 애플리케이션을 공용 인스턴스와 동일한 데이터베이스에 연결합니다.


답변

특정 IP 주소 / 사용자 및 제한된 수명에 바인딩 된 고유 한 세션 ID를 생성 할 수 있습니다. 사용자가 애플리케이션 프런트 엔드 JavaScript 코드를 다운로드하면 생성 된 세션 ID를 JavaScript 소스 코드에 삽입합니다. 세션 ID는 API에 대한 모든 요청에 ​​첨부되며 속도 제한이 해제됩니다.

ID는 단일 IP 주소, 사용자 및 제한된 시간 동안 만 유효하기 때문에 스푸핑을 위해 단순히 복사 할 수 없습니다. 따라서 공격자는 페이지를 호출하고 JavaScript 소스에서 키를 걸러 내거나 새로운 사용자가 사용하려고 할 때마다 Ajax 요청을 가로 채지 않도록해야합니다.

다른 옵션 :

자신의 애플리케이션에 대한 프록시를 설정하고 난독 화를 사용합니다. 프록시에 대한 Ajax 요청은 실제 API 호출과 다른 이름을 사용하며 프록시는이를 다시 변환합니다. 따라서 애플리케이션은 getDocument실제 API를 호출하지 않지만 getFELSUFDSKJE프록시를 호출 합니다. 프록시는이 호출을 getDocument로 다시 변환하고 실제 속도 제한 API로 전달합니다.

실제 API는 프록시의 요청 속도를 제한하지 않습니다.

그리고 다른 사람들이 자신의 애플리케이션에 프록시를 사용하지 않도록 매일 난독 화 체계를 변경합니다. 난독 화 된 호출 이름은 JavaScript 소스 코드에서 자동으로 생성되고 프록시에서 구성 될 수 있습니다.

이것을 사용하려는 클라이언트는 프록시를 사용하기 위해 변경된 난독 화를 따라 잡아야합니다. 또한 로깅에 referrer-headers 등을 사용할 수 있으므로 프록시를 사용하는 사람을 찾을 수 있습니다. 또는 난독 화 체계를 변경할 때이를 포착하십시오.