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ą)
Sprawdź stronę odsyłającą z nagłówkiem hosta. - Błąd, ponieważ strona odsyłająca jest łatwa do sfałszowania.
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.
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?
źródło
Odpowiedzi:
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.
źródło
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ą.
źródło
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.
źródło
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
źródło
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.
źródło
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.
źródło
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ć
getDocument
twojego 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.
źródło
źródło
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
n
konta, dając Ci nawetn
razy 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.
źródło