Jak zapobiegać atakom zagnieżdżonym na serwerze GraphQL/Apollo?

Jak zapobiec zagnieżdżonemu atakowi na serwer Apollo za pomocą zapytania takiego jak:

{
  authors {
    firstName
    posts {
      title
      author {
        firstName
        posts{
          title
          author {
            firstName
            posts {
              title
              [n author]
                [n post]
            }
          }
        }
      }
    }
  }
}

Innymi słowy, jak można ograniczyć liczbę rekursji zgłaszanych w zapytaniu? To może być potencjalna luka w serwerze.

Author: rdrey, 2016-05-20

4 answers

W chwili pisania tego tekstu nie ma wbudowanej funkcji w GraphQL-js lub Apollo Server, która poradziłaby sobie z tym problemem, ale jest to coś, co zdecydowanie powinno mieć proste rozwiązanie, ponieważ GraphQL staje się bardziej popularny. Problem ten można rozwiązać za pomocą kilku podejść na kilku poziomach stosu i zawsze należy go łączyć z ograniczeniem szybkości, aby ludzie nie mogli wysyłać zbyt wielu zapytań na twój serwer(jest to również potencjalny problem z REST).

Wymienię tylko wszystkie różne metody, które mogę wymyślić, i postaram się utrzymać tę odpowiedź na bieżąco, ponieważ te rozwiązania są zaimplementowane w różnych serwerach GraphQL. Niektóre z nich są dość proste, a niektóre są bardziej złożone.

  1. query validation : na każdym serwerze GraphQL pierwszym krokiem do uruchomienia zapytania jest validation - tutaj serwer próbuje określić, czy w zapytaniu są jakieś poważne błędy, dzięki czemu możemy uniknąć korzystania z rzeczywistych zasobów serwera, jeśli uda nam się znaleźć z przodu jest jakiś błąd składni lub nieprawidłowy argument. GraphQL-JS zawiera wybór domyślnych reguł , które mają format podobny do ESLint. Podobnie jak istnieje reguła do wykrywania nieskończonych cykli we fragmentach , można napisać regułę walidacji, aby wykrywać zapytania o zbyt dużym zagnieżdżeniu i odrzucać je na etapie walidacji.
  2. query timeout : Jeśli nie jest możliwe wykrycie, że zapytanie będzie zbyt zasobochłonne statycznie (być może nawet płytkie zapytania mogą być bardzo drogie!), wtedy możemy po prostu dodać timeout do wykonania zapytania. Ma to kilka zalet: (1) jest to twardy limit, który nie jest zbyt trudny do rozumowania, i (2) pomoże to również w sytuacjach, w których jeden z backendów zajmuje zbyt wiele czasu, aby odpowiedzieć. W wielu przypadkach użytkownik aplikacji wolałby brakujące pole niż czekanie 10 + sekund, aby uzyskać odpowiedź.
  3. Query whitelisting : jest to prawdopodobnie najbardziej zaangażowana metoda, ale możesz skompiluj listę dozwolonych zapytań z wyprzedzeniem i sprawdź wszystkie przychodzące zapytania względem tej listy. Jeśli Twoje zapytania są całkowicie statyczne (nie generujesz dynamicznych zapytań na kliencie za pomocą przekaźnika), jest to najbardziej niezawodne podejście. Możesz użyć automatycznego narzędzia do wyciągania ciągów zapytań z aplikacji po ich wdrożeniu, dzięki czemu w rozwoju piszesz dowolne zapytania, ale w produkcji tylko te, które chcesz, są przepuszczane. Kolejną zaletą takiego podejścia jest czy możesz całkowicie pominąć walidację zapytań, ponieważ wiesz, że wszystkie możliwe zapytania są już ważne. Aby uzyskać więcej korzyści z zapytań statycznych i białej listy, przeczytaj ten post: https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a
  4. ograniczanie kosztów zapytań : (dodane w edycji) podobnie do terminów zapytań, można przypisać koszt do różnych operacji podczas wykonywania zapytań, na przykład zapytania bazy danych, i ograniczyć całkowity koszt klienta jest w stanie użyć na zapytanie. Można to połączyć z ograniczeniem maksymalnej równoległości pojedynczego zapytania, dzięki czemu można zapobiec wysyłaniu przez Klienta czegoś, co inicjuje tysiące równoległych żądań do twojego zaplecza.

(1) i (2) w szczególności są prawdopodobnie czymś, co każdy serwer GraphQL powinien mieć domyślnie, zwłaszcza, że wielu nowych programistów może nie być świadomych tych obaw. (3) będzie działać tylko dla niektórych rodzajów aplikacji, ale może być dobrym wyborem, gdy tam są bardzo rygorystyczne wymagania dotyczące wydajności lub bezpieczeństwa.

 39
Author: stubailo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-18 06:29:51

Aby uzupełnić punkt (4) w odpowiedzi stubailo, oto kilka węzłów.implementacje js nakładające ograniczenia kosztów i głębokości na przychodzące dokumenty GraphQL.

Są to reguły niestandardowe, które uzupełniają fazę walidacji.

 8
Author: Andy Carlson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 23:57:01

Zmienną na białej liście zapytań jest podpisywanie zapytań .

Podczas procesu budowania każde zapytanie jest podpisywane kryptograficznie przy użyciu tajemnicy, która jest współdzielona z serwerem, ale nie jest dołączona do klienta. Następnie w czasie wykonywania serwer może zweryfikować, czy zapytanie jest prawdziwe.

Przewaga nad białą listą polega na tym, że pisanie zapytań w kliencie nie wymaga żadnych zmian na serwerze. Jest to szczególnie cenne, jeśli wielu klientów uzyskuje dostęp do tego samego serwera (np., aplikacje komputerowe i mobilne).

 1
Author: Tamlyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-29 16:04:42

Dla zapytania ograniczenie kosztów można użyć graphql-analiza kosztów

Jest to Reguła walidacji, która przetwarza zapytanie przed jego wykonaniem. Na serwerze GraphQL wystarczy przypisać konfigurację kosztów dla każdego pola mapy typu schematu, który chcesz.

 1
Author: Schrax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 10:30:16