Dogfooding naszego własnego interfejsu API z ograniczoną szybkością

117

Przegląd:

Moja firma opracowała API z ograniczoną opłatą. Nasz cel jest dwojaki:

  • O: Stwórz silny ekosystem programistów wokół naszego produktu.
  • B: Zademonstruj możliwości naszego API, używając go do sterowania naszą własną aplikacją.

Wyjaśnienie: po co w ogóle ograniczać stawki?

Ograniczamy nasze API, ponieważ sprzedajemy je jako dodatek do naszego produktu. Anonimowy dostęp do naszego API ma bardzo niski próg wywołań API na godzinę, podczas gdy nasi płatni klienci mają prawo do 1000 lub więcej wywołań na godzinę.

Problem:

Nasz ograniczony cenowo interfejs API świetnie nadaje się do ekosystemu programistów, ale abyśmy mogli go przetestować, nie możemy pozwolić, aby był on ograniczony do tego samego ograniczenia stawki. Front-end naszego API to cały JavaScript, który wykonuje bezpośrednie wywołania Ajax do API.

Więc pytanie brzmi:

Jak zabezpieczyć interfejs API, aby można było usunąć ograniczenie szybkości, gdy w procesie usuwania takiego ograniczenia nie można łatwo sfałszować?

Eksplorowane rozwiązania (i dlaczego nie działają)

  1. Sprawdź stronę odsyłającą z nagłówkiem hosta. - Błąd, ponieważ strona odsyłająca jest łatwa do sfałszowania.

  2. Użyj HMAC, aby utworzyć podpis na podstawie żądania i wspólnego hasła, a następnie zweryfikuj żądanie na serwerze. - Błąd, ponieważ sekret i algorytm można łatwo określić, patrząc na język JavaScript w interfejsie użytkownika.

  3. Proxy żądanie i podpisanie żądania w proxy - nadal wadliwe, ponieważ samo proxy ujawnia API.

Pytanie:

Oczekuję błyskotliwych umysłów w Stack Overflow, aby przedstawić alternatywne rozwiązania. Jak rozwiązałbyś ten problem?

Jason Waldrip
źródło
13
Nie możesz. Jeśli twoje własne wykorzystanie interfejsu API, którego nie chcesz ograniczać do ograniczania szybkości, pochodzi tylko z publicznych stron internetowych, nie możesz zrobić nic bezpiecznego z tych publicznych stron internetowych, ponieważ, jak już wiesz, są żadnych tajemnic na publicznych stronach internetowych. Więc co możesz robić na swoich stronach internetowych, więc każdy inny może.
jfriend00
28
Czy na pewno masz problem z ograniczeniem stawki do rozwiązania w testach? Każdy użytkownik korzystający z Twojej witryny i stron internetowych powinien wyglądać na zupełnie innego użytkownika niż kod ograniczający szybkość. Dlatego po prostu upewnij się, że każda strona internetowa działa zgodnie z normalnymi regułami ograniczania szybkości i wszystko powinno być w porządku. Zakładając, że Twoje ograniczenie stawki dotyczy jednego klienta, jeden użytkownik nie będzie miał nic wspólnego z żadnym innym użytkownikiem.
jfriend00
6
Dlaczego nie wziąć pod uwagę rozwiązania API Management, które zapewnia ograniczanie szybkości i dławienie w zakresie na użytkownika, na rolę / uprawnienia lub zakres aplikacji. Np. Wso2 api manger
MiddlewareManiac
28
Podczas testów wewnętrznych wykryto poważny problem z publicznym interfejsem API (polegający na tym, że limit szybkości jest za niski) i zamiast go naprawić, próbujesz go obejść. Po co testować, skoro masz zignorować napotkane problemy?
user253751

Odpowiedzi:

93

Ponieważ twój własny klient JavaScript ma bezpośredni dostęp do API, każdy będzie mógł zobaczyć, co robi i naśladować to, w tym użyć tego samego klucza API. Możesz spróbować to utrudnić, na przykład zaciemniając swój kod lub stawiając różne przeszkody na drodze, ale ty i osoba, którą próbujesz powstrzymać, macie zasadniczo ten sam dostęp. Zamiast próbować tworzyć różnicę w uprawnieniach, musisz zbudować system, w którym jest całkowicie OK, że nieoficjalny klient korzysta z całego dostępu w swoim zakresie, ale system jest zorganizowany w taki sposób, że oficjalne użycie przez wszystkich klientów jest większy.

Odbywa się to często za pomocą tokenów dostępu dla poszczególnych użytkowników, a nie jednego tokenu dla całej aplikacji. Limit każdego tokena powinien być wystarczający dla typowego użycia interfejsu API, ale restrykcyjny dla kogoś, kto próbuje go nadużywać. Na przykład 100 połączeń na minutę może wystarczyć do obsługi typowego przeglądania, ale jeśli chcę Cię zeskrobać, nie mogę tego zrobić skutecznie przy takim budżecie.

Zawsze będzie wyścig zbrojeń - mogę ominąć ten limit, tworząc wiele kont użytkowników botów. Jest to jednak całkiem rozwiązany problem, jeśli po prostu dodasz captcha do przepływu rejestracji, niewielkim kosztem dla prawdziwego człowieka. Kiedy wchodzisz w te scenariusze, wszystko jest tylko kompromisem między wygodą a ograniczeniami. Nigdy nie znajdziesz czegoś całkowicie kuloodpornego, więc skup się na zrobieniu tego wystarczająco dobrze i poczekaj, aż ktoś cię wykorzysta, aby dowiedzieć się, gdzie są dziury.

Kristján
źródło
8
Akceptując to jako najlepszą odpowiedź. Droga, którą zdecydowaliśmy się obrać, to użycie tokenów JWT o niższej ważności i zwiększenie limitu szybkości tych połączeń. Zakodujemy dodatkowe informacje w tokenie, aby poinformować zaplecze o wyższym limicie szybkości. Ponieważ te tokeny są bezpiecznie podpisane na zapleczu, nie powinno być problemu z podszywaniem się. Ktoś mógłby nadal używać tokena, ale jego ważność wygasłaby po kilku dniach, a zatem utrzymanie dowolnego rodzaju bota byłoby trudniejsze do wykonania.
Jason Waldrip
33

Jeśli powoduje to problem, spowoduje to problem w Twoim domniemanym ekosystemie programistów (np. Gdy będą próbowali opracować alternatywny interfejs użytkownika). Jeśli naprawdę jesz własną karmę dla psów, spraw, aby interfejs API (i ograniczenie szybkości) działały w Twojej aplikacji. Oto parę sugestii:

  • Nie ograniczaj szybkości według adresu IP. Raczej ograniczenie szybkości przez coś związanego z użytkownikiem, np. Jego identyfikator użytkownika. Zastosuj limit szybkości na etapie uwierzytelniania.

  • Zaprojektuj swój interfejs API tak, aby użytkownicy nie musieli go wywoływać w sposób ciągły (np. Wywołanie listy, które zwraca wiele wyników, zamiast powtarzającego się wywołania, które za każdym razem zwraca jeden element)

  • Zaprojektuj swoją aplikację internetową z tymi samymi ograniczeniami, których oczekujesz od ekosystemu programisty, tj. Upewnij się, że możesz zaprojektować ją z rozsądnymi szybkościami ograniczania.

  • Upewnij się, że zaplecze jest skalowalne (najlepiej w poziomie), więc nie musisz narzucać ograniczania przepustowości na tak niskich poziomach, że faktycznie powoduje to problem w interfejsie użytkownika.

  • Upewnij się, że dławienie jest w stanie poradzić sobie z seriami, a także ograniczyć długoterminowe nadużycia.

  • Upewnij się, że dławienie wykonuje rozsądne działania dostosowane do nadużycia, które chcesz usunąć. Na przykład rozważ umieszczenie w kolejce lub opóźnianie łagodnych nadużyć zamiast odrzucania połączenia. Większość frontonów internetowych otwiera jednocześnie tylko cztery jednoczesne połączenia. Jeśli opóźnisz próbę otwarcia piątej, trafisz tylko w przypadek, w którym używają CLI w tym samym czasie, co klient sieciowy (nie ma dwóch klientów internetowych). Jeśli opóźnisz n-te wywołanie API bez przerwy, zamiast je zawieść, użytkownik końcowy zobaczy, że wszystko spowolni, a nie zepsuje. Jeśli połączysz to z kolejkowaniem tylko wywołań N API naraz, trafisz tylko w osoby, które równolegle wykonują dużą liczbę wywołań API, co prawdopodobnie nie jest zachowaniem, którego chcesz - np. 100 jednoczesnych wywołań API, wtedy przerwa na godzinę jest zwykle duża gorzej niż 100 kolejnych wywołań API w ciągu godziny.

Czy to nie odpowiada na Twoje pytanie? Cóż, jeśli naprawdę musisz zrobić to, o co prosisz, ogranicz szybkość na etapie uwierzytelniania i zastosuj inny limit szybkości w zależności od grupy, do której należy twój użytkownik. Jeśli używasz jednego zestawu poświadczeń (używanego przez twoich programistów i zespół QA), otrzymasz wyższy limit szybkości. Ale od razu możesz zobaczyć, dlaczego to nieuchronnie doprowadzi cię do twojego ekosystemu, widząc problemy, których Twoi deweloperzy i zespół kontroli jakości nie widzą.

abligh
źródło
11

Kup swój produkt. Zostań swoim płatnym klientem.

„Anonimowy dostęp do naszego interfejsu API ma bardzo niski próg wywołań API na godzinę, podczas gdy nasi płatni klienci mogą uzyskać do 1000 połączeń na godzinę lub więcej”.

Pomaga to również przetestować system z perspektywy klienta.

jkdev
źródło
1
Oczywista odpowiedź. Żadnego oszukiwania ani udawania!
wizzwizz4
9

Niestety nie ma na to idealnego rozwiązania.

Ogólne podejście polega zazwyczaj na zapewnieniu pliku fałszywego plikusposób na identyfikację klientów (np. identyfikator, wersja, klucz API - np.), rejestrowanie przez klientów informacji o sobie, które mogą służyć do ograniczenia dostępu (np. klient jest serwerem w danym zakresie adresów IP, więc zezwalaj tylko wywołującym w tym zakresie; np. klient to JavaScript, ale dostarczany tylko do określonej kategorii przeglądarki, więc zezwalaj tylko na dostęp do żądań HTTP, które określają określone ciągi agentów użytkownika; itp.), a następnie użyj uczenia maszynowego / wzorca rozpoznawanie w celu wykrycia nietypowego użycia, które prawdopodobnie jest fałszywym klientem, a następnie odrzucenia ruchu od tych fałszywych klientów (lub potwierdzenia z klientami, że te zastosowania rzeczywiście nie pochodzą od legalnego klienta, zastąp ich fałszywe poświadczenia, a następnie zablokuj dalszy ruch przy użyciu starszego sfałszowane dane logowania).

Możesz nieco utrudnić fałszowanie, używając wielu warstw klucza. Na przykład udostępniasz długoterminowe poświadczenie, które znajduje się na serwerze (i może być używane tylko w ograniczonym zestawie zakresów adresów IP), aby wykonać wywołanie API, które rejestruje informacje o kliencie (np. Kliencie użytkownika) i zwraca klucz po stronie klienta o krótszej żywotności, który jest syndykowany w języku JavaScript do użycia na kliencie dla żądań interfejsu API po stronie klienta. To również jest niedoskonałe (spoofer może wysłać to samo wywołanie serwera, aby uzyskać poświadczenie), ale będzie to trudniejsze, jeśli zwrócony klucz API zostanie zawarty w zaciemnionym (i często zmieniającym się) języku JavaScript lub HTML (co utrudniłoby wiarygodnie wyodrębnić z odpowiedzi). Zapewnia to również sposób na łatwiejsze wykrywanie podszywania się; klucz po stronie klienta jest teraz powiązany z konkretnym klientem (np

Michael Aaron Safyan
źródło
8

Zakładając, że dana aplikacja musi być publicznie otwarta, nie masz dużego wyboru:

Wybierz inny sposób, aby zademonstrować możliwości swojego interfejsu API. Na przykład napisz taką aplikację i udostępnij jej źródło, ale w rzeczywistości nie uruchamiaj tego kodu. Upewnij się jednak, że jest dobrze udokumentowany, aby każdy mógł go wdrożyć i zobaczyć, jak działa (podlega ograniczeniu).

Uruchomiona aplikacja musiałaby zostać zmieniona, aby uniknąć żądań interfejsu API po stronie klienta i byłaby bardziej renderowana na serwerze. Nadal możesz testować swój interfejs API, ale nie w oczywisty sposób - wysyłaj bezpieczne żądania do wolnego od ograniczania przepustowości interfejsu API po stronie serwera.

Dostosuj ograniczenie prędkości aby aplikacja mogła działać, i zainwestuj w optymalizację wydajności w celu obsługi obciążenia.

I tak, przede wszystkim pozwól, aby rdzeń API był wolny od dławienia i trzymaj go w prywatnej sieci. Ogranicz przepustowość w osobnej publicznie dostępnej warstwie.

Anton Strogonoff
źródło
4

Czy możesz postawić oddzielne wystąpienie interfejsu użytkownika i pozbawionego przepustnicy interfejsu API, a następnie ograniczyć dostęp do adresów IP pochodzących z Twojej organizacji?

Np. Wdróż całość za firmową zaporą ogniową i dołącz aplikację do tej samej bazy danych, co instancja publiczna, jeśli chcesz udostępniać dane między instancjami.

Peter Mortensen
źródło
4

Możesz spróbować wygenerować unikalny identyfikator sesji, powiązany z określonym adresem IP / użytkownikiem i ograniczonym czasem życia. Gdy użytkownik pobiera kod JavaScript frontendu aplikacji, wstrzyknij wygenerowany identyfikator sesji do kodu źródłowego JavaScript. Identyfikator sesji zostanie dołączony do każdego żądania wysyłanego do Twojego interfejsu API, a limit stawki zostanie zniesiony.

Identyfikatora nie można po prostu skopiować w celu sfałszowania, ponieważ jest ważny tylko dla jednego adresu IP, użytkownika i ograniczonego czasu. Tak więc przeciwnik musiałby wywołać twoją stronę i odfiltrować klucz ze źródła JavaScript lub przed przechwyceniem żądania Ajax za każdym razem, gdy nowy użytkownik chce go użyć.

Inna opcja:

Skonfiguruj serwer proxy dla własnej aplikacji i użyj zaciemniania. Żądania Ajax do proxy używają innych nazw niż rzeczywiste wywołania API, a proxy tłumaczy je z powrotem. Więc twoja aplikacja nie będzie wywoływać getDocumenttwojego prawdziwego API, ale będzie wywoływaćgetFELSUFDSKJE twoje proxy. Proxy przetłumaczy to wywołanie z powrotem na getDocument i przekaże je do rzeczywistego API z ograniczoną szybkością.

Twój rzeczywisty interfejs API nie ogranicza szybkości żądań przez serwer proxy.

Aby inne osoby nie używały Twojego serwera proxy do własnych aplikacji, codziennie zmieniasz schemat zaciemniania. Ukryte nazwy wywołań mogą być generowane automatycznie w kodzie źródłowym JavaScript i konfigurowane w proxy.

Klient, który chciałby z tego skorzystać, musiałby również nadążać za zmieniającymi się zaciemnieniami, aby korzystać z serwera proxy. Nadal możesz używać nagłówków stron odsyłających i podobnych do logowania, dzięki czemu możesz znajdować osoby korzystające z serwera proxy. Lub złap je podczas zmiany schematu zaciemniania.

Falco
źródło
3
  • Źródłowe adresy IP na białej liście
  • Użyj VPN , dodaj członków VPN do białej listy
  • Rozwiązanie proxy lub dodatek do przeglądarki, który dodaje nagłówki HTTP, powinno wystarczyć, jeśli możesz zabezpieczyć serwer proxy i nie martwisz się atakami MITM, które węszą ruch
  • Każde rozwiązanie obejmujące sekrety może złagodzić skutki wycieków dzięki codziennej rotacji sekretów
the8472
źródło
Te rozwiązania nie mają zastosowania do frontendowego klienta WWW. Idealne, jeśli dostęp do interfejsu API był na zapleczu.
Jason Waldrip
@jason, wszystkie można zastosować do interfejsu użytkownika
the8472
2

Skonfiguruj wiele kont i wybierz jedno z nich losowo na każde żądanie lub zmieniaj używane co godzinę. W ten sposób możesz rozłożyć obciążenie na nkonta, dając Ci nawet nrazy wyższe limity.

Uważaj na przypadkowe zamknięcie się, jeśli próbujesz znaleźć innych użytkowników, którzy to robią, jeśli nie jest to dozwolone dla klientów.

Filip Haglund
źródło