Dlaczego Google wyprzedza while (1); na ich odpowiedzi JSON?

4074

Dlaczego Google dodaje while(1);do swoich (prywatnych) odpowiedzi JSON?

Na przykład, oto odpowiedź podczas włączania i wyłączania kalendarza w Kalendarzu Google :

while (1);
[
  ['u', [
    ['smsSentFlag', 'false'],
    ['hideInvitations', 'false'],
    ['remindOnRespondedEventsOnly', 'true'],
    ['hideInvitations_remindOnRespondedEventsOnly', 'false_true'],
    ['Calendar ID stripped for privacy', 'false'],
    ['smsVerifiedFlag', 'true']
  ]]
]

Zakładam, że ma to na celu powstrzymanie ludzi przed robieniem eval()tego, ale tak naprawdę wszystko, co musicie zrobić, to wymienić whilei ustawić. Zakładam, że zapobieganie ewaluacji polega na upewnieniu się, że ludzie piszą bezpieczny kod parsujący JSON.

Widziałem to również w kilku innych miejscach, ale o wiele bardziej w Google (Poczta, Kalendarz, Kontakty itp.) O dziwo, Dokumenty Google zaczynają się od &&&START&&&, a Kontakty Google wydają się zaczynać while(1); &&&START&&&.

Co tu się dzieje?

Pęto
źródło
45
Uważam, że twoje pierwsze wrażenie jest prawidłowe. Jeśli zaczniesz szukać kodu i spróbujesz przyciąć strumień wejściowy w zależności od źródła, zastanów się i zrób to w bezpieczny (i ze względu na działania Google, łatwiej) sposób.
Esteban Küber
34
prawdopodobnie kolejne pytanie: dlaczego Google )]}'zastępuje teraz zamiast while(1);? Czy odpowiedzi byłyby takie same?
Gizmo
3
Uniemożliwiłoby to eval, ale nie w nieskończonej pętli.
Mardoxx,
9
To )]}'może być również zapisać bajtów, takich jak Facebook stosowanego for(;;);co oszczędza jeden bajt :)
Gras podwójne
3
Inorder, aby zapobiec ujawnieniu JSON hijacking
Jsona,

Odpowiedzi:

4293

Zapobiega przejęciu JSON , poważnemu problemowi bezpieczeństwa JSON, który został oficjalnie naprawiony we wszystkich głównych przeglądarkach od 2011 roku za pomocą ECMAScript 5.

Przemyślany przykład: powiedzmy, że Google ma adres URL, mail.google.com/json?action=inboxktóry zwraca pierwsze 50 wiadomości z Twojej skrzynki odbiorczej w formacie JSON. Złe witryny internetowe w innych domenach nie mogą wysyłać żądań AJAX w celu uzyskania tych danych ze względu na zasady tego samego pochodzenia, ale mogą zawierać adres URL za pomocą <script>tagu. URL odwiedza ze swoimi ciasteczek, a przez nadrzędne globalnej tablicy konstruktora lub metody dostępowe mogą mieć metoda wywoływana, gdy obiekt (tablica lub hash) atrybut jest ustawiony, umożliwiając im odczytać zawartość JSON.

while(1);Lub &&&BLAH&&&Zapobiega to: żądanie AJAX co mail.google.combędzie mieć pełny dostęp do zawartości tekstowej i może go znieść. Ale <script>wstawienie znacznika ślepo wykonuje JavaScript bez przetwarzania, co powoduje nieskończoną pętlę lub błąd składniowy.

Nie rozwiązuje to problemu fałszowania żądań między witrynami .

rjh
źródło
228
Dlaczego prośba o uzyskanie tych danych nie wymaga tokenu CSRF?
Jakub P.
235
Czy for(;;);wykonuje tę samą pracę? Widziałem to w odpowiedziach ajax na Facebooku.
Król Julien
183
@JakubP. Przechowywanie i utrzymywanie tokenów CSRF na skalę Google wymaga dużej ilości infrastruktury i kosztów.
abraham
127
@JakubP. tokeny anti-CSRF bałagają się buforowania i wymagają pewnej ilości oceny oceny kryptograficznej po stronie serwera. W skali Google wymagałoby to dużo procesora. Ten rodzaj odciąża go do klienta.
bluesmoon
96
Wydaje mi się, że lepszym sposobem byłoby zezwolenie serwerowi na wysyłanie JSON tylko wtedy, gdy został ustawiony prawidłowy nagłówek. Możesz to zrobić w wywołaniu AJAX, ale nie za pomocą znaczników skryptu. W ten sposób poufne informacje nigdy nie są wysyłane i nie musisz polegać na bezpieczeństwie po stronie przeglądarki.
mcv,
574

Zapobiega ujawnieniu odpowiedzi poprzez przejęcie JSON.

Teoretycznie treść odpowiedzi HTTP jest chroniona przez tę samą zasadę pochodzenia: strony z jednej domeny nie mogą uzyskać żadnych informacji ze stron w drugiej domenie (chyba że jest to wyraźnie dozwolone).

Osoba atakująca może zażądać stron w innych domenach w Twoim imieniu, np. Przy użyciu tagu <script src=...>lub <img>, ale nie może uzyskać żadnych informacji o wyniku (nagłówki, treść).

Tak więc, jeśli odwiedzisz stronę atakującego, nie będzie mógł odczytać twojego e-maila z gmail.com.

Tyle że podczas używania znacznika skryptu do żądania treści JSON, JSON jest wykonywany jako JavaScript w środowisku kontrolowanym przez osobę atakującą. Jeśli atakujący może zastąpić konstruktor macierzy lub obiektów lub inną metodę używaną podczas budowy obiektu, wszystko w JSON przejdzie przez kod atakującego i zostanie ujawnione.

Należy zauważyć, że dzieje się tak w momencie wykonywania JSON jako Javascript, a nie w momencie jego analizy.

Istnieje wiele środków zaradczych:

Upewnienie się, że JSON nigdy się nie uruchamia

Umieszczając while(1);instrukcję przed danymi JSON, Google upewnia się, że dane JSON nigdy nie są wykonywane jako JavaScript.

Tylko uzasadniona strona może uzyskać całą zawartość, usunąć while(1);i przeanalizować resztę jako JSON.

Rzeczy na przykład for(;;);były widziane na Facebooku z takimi samymi wynikami.

Upewnij się, że JSON nie jest prawidłowym Javascript

Podobnie dodanie nieprawidłowych tokenów przed JSON, na przykład &&&START&&&, gwarantuje, że nigdy nie zostanie ono wykonane.

Zawsze zwracaj JSON z obiektem na zewnątrz

Jest to OWASPzalecany sposób ochrony przed porwaniem JSON i jest mniej inwazyjny.

Podobnie jak poprzednie środki zaradcze, upewnia się, że JSON nigdy nie jest wykonywany jako JavaScript.

Prawidłowy obiekt JSON, jeśli nie jest przez niego niczym zamknięty, nie jest poprawny w JavaScript:

eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :

Jest to jednak poprawne JSON:

JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}

Upewnij się, że zawsze zwracasz obiekt na najwyższym poziomie odpowiedzi. Upewnij się, że JSON nie jest poprawnym skryptem JavaScript, a jednocześnie jest poprawnym JSON.

Jak zauważył @hvd w komentarzach, pusty obiekt {}jest poprawnym skryptem Javascript, a znajomość obiektu jest pusta może być cenną informacją.

Porównanie powyższych metod

Sposób OWASP jest mniej ingerujący, ponieważ nie wymaga zmian w bibliotece klienta i przesyła prawidłowy JSON. Nie jest jednak pewne, czy poprzednie lub przyszłe błędy przeglądarki mogłyby to rozwiązać. Jak zauważył @oriadam, nie jest jasne, czy dane mogą być wyciekane w wyniku błędu analizy poprzez obsługę błędów, czy nie (np. Window.onerror).

Sposób Google wymaga od biblioteki klienta obsługi automatycznej deserializacji i może być uważany za bezpieczniejszy w przypadku błędów przeglądarki.

Obie metody wymagają zmian po stronie serwera, aby uniknąć sytuacji, w której programiści mogliby przypadkowo wysłać wrażliwy JSON.

Arnaud Le Blanc
źródło
23
Rekomendacja OWASP jest interesująca ze względu na swoją prostotę. Czy ktoś wie, dlaczego sposób Google jest bardziej bezpieczny?
funroll
18
Uważam, że nie jest w żaden sposób bardziej bezpieczny. Podanie OWASP wydaje się wystarczająco dobrym powodem do +1.
30
Warto zwrócić uwagę na to, dlaczego zwracanie literału obiektu zawodzi w scripttagu lub evalfunkcji. Nawiasy klamrowe {}można interpretować jako blok kodu lub literał obiektu, a sam JavaScript preferuje ten pierwszy. Jako blok kodu jest oczywiście nieprawidłowy. Zgodnie z tą logiką nie widzę żadnych przewidywalnych zmian w przyszłym zachowaniu przeglądarki.
Manngo,
16
Zły kod nie wystarcza, ponieważ osoba atakująca może również przejąć funkcję obsługi błędów skryptu w przeglądarce ( window.onerror). Nie jestem pewien, co się dzieje onerrorz błędami składniowymi. Myślę, że Google też nie był pewien.
oriadam
12
„Prawidłowy obiekt JSON, jeśli nie jest przez niego niczym zamknięty, nie jest prawidłowy w JavaScript:” - Z wyjątkiem trywialnego przypadku pustego obiektu ( {}), który jest również prawidłowym pustym blokiem. Jeśli wiedza o tym, że obiekt jest pusty, może sama w sobie być cenną informacją, może to być przydatne.
371

Ma to na celu zapewnienie, że inna strona nie będzie w stanie wykonać paskudnych sztuczek w celu kradzieży danych. Na przykład, zastępując konstruktor tablicy , a następnie włączając ten adres URL JSON za pomocą <script>znacznika, złośliwa witryna innej firmy może ukraść dane z odpowiedzi JSON. Po umieszczeniu while(1);na początku skrypt zawiesi się.

Z drugiej strony żądanie tej samej witryny przy użyciu XHR i oddzielnego parsera JSON może z łatwością zignorować while(1);prefiks.

bdonlan
źródło
6
Technicznie, „normalny” parser JSON powinien dawać błąd, jeśli masz prefiks.
Matthew Crumley
12
Atakujący użyliby zwykłego starego <script>elementu, a nie XHR.
Laurence Gonsalves
9
@Mathew, jasne, ale możesz je usunąć przed przekazaniem danych do analizatora składni JSON. Nie możesz tego zrobić za pomocą <script>tagu
bdonlan
7
Czy są tego jakieś przykłady? Odwołanie do konstruktora tablic jest ponownie przywoływane, ale jest to błąd, który już dawno został naprawiony. Nie rozumiem, w jaki sposób można uzyskać dostęp do danych otrzymanych za pośrednictwem znacznika skryptu. Chciałbym zobaczyć fałszywą implementację, która działa w najnowszej przeglądarce.
Dennis G,
7
@joeltine, nie, to nie jest. Zobacz stackoverflow.com/questions/16289894/… .
111

Utrudniłoby to stronom trzecim wstawienie odpowiedzi JSON do dokumentu HTML ze <script>znacznikiem. Pamiętaj, że <script>tag jest zwolniony z zasad tego samego pochodzenia .

Daniel Vassallo
źródło
21
To tylko połowa odpowiedzi. Gdyby nie sztuczka polegająca na zastąpieniu konstruktorów Objecti Array, wykonanie prawidłowej odpowiedzi JSON tak, jakby to był JavaScript, byłoby całkowicie nieszkodliwe we wszystkich okolicznościach. Tak, while(1);uniemożliwia wykonanie odpowiedzi jako JavaScript, jeśli jest celem <script>tagu, ale twoja odpowiedź nie wyjaśnia, dlaczego jest to konieczne.
Mark Amery
ale jak to zapobiegnie iframe
Ravinder Payal
Tag skryptu nigdy nie jest zwolniony z tej samej zasady pochodzenia. Czy możesz mi to wyjaśnić?
Suraj Jain
82

Uwaga : od 2019 r. Wiele starych luk w zabezpieczeniach, które prowadzą do środków zapobiegawczych omówionych w tym pytaniu, nie są już problemem we współczesnych przeglądarkach. Poniższą odpowiedź pozostawię jako ciekawostkę historyczną, ale tak naprawdę cały temat zmienił się radykalnie od 2010 roku (!!), kiedy o to zapytano.


Zapobiega to wykorzystaniu go jako celu prostego <script>tagu. (Cóż, nie przeszkadza to, ale sprawia, że ​​jest nieprzyjemny.) W ten sposób źli ludzie nie mogą po prostu umieścić tego tagu skryptu na swojej stronie i polegać na aktywnej sesji, aby umożliwić pobranie treści.

edycja - zanotuj komentarz (i inne odpowiedzi). Emisja ma do czynienia z zniweczony wbudowanym w obiektach, a konkretnie Objecti Arraykonstruktorów. Można je zmienić w taki sposób, aby w przeciwnym razie nieszkodliwy JSON po przeanalizowaniu mógł wywołać kod atakującego.

Pointy
źródło
17
To tylko połowa odpowiedzi. Gdyby nie sztuczka polegająca na zastąpieniu konstruktorów Objecti Array, wykonanie prawidłowej odpowiedzi JSON tak, jakby to był JavaScript, byłoby całkowicie nieszkodliwe we wszystkich okolicznościach. Tak, while(1);uniemożliwia wykonanie odpowiedzi jako JavaScript, jeśli jest celem <script>tagu, ale twoja odpowiedź nie wyjaśnia, dlaczego jest to konieczne.
Mark Amery
11

Ponieważ <script>znacznik jest zwolniony z tej samej zasady pochodzenia, co jest koniecznością w świecie bezpieczeństwa, while(1)po dodaniu do odpowiedzi JSON zapobiega niewłaściwemu wykorzystaniu go w <script>znaczniku.

Krishna Ganeriwal
źródło