Wszystkie artykuły
Szczegółowa analiza8 min czytania

Weryfikuj powiadomienia serwera App Store, zanim zareagujesz na zwrot, bo każdy może wysłać żądanie na Twój adres webhooka

Powiadomienie o zwrocie to tylko żądanie HTTPS, dopóki nie sprawdzisz jego podpisu. Oto jak weryfikować powiadomienia serwera App Store i wiadomości RTDN z Google Play, co podpisuje każdy ze sklepów i ile kosztuje Cię sfałszowany lub błędnie odrzucony zwrot.

Mosiężna pieczęć do laku i zapieczętowana koperta obok laptopa na biurku w ciepłym świetle lampy, obraz tego, dlaczego warto weryfikować powiadomienia serwera App Store, zanim się im zaufa

Najważniejsze wnioski

  • Apple wysyła każde powiadomienie serwera App Store w wersji 2 jako signedPayload, czyli JSON Web Signature złożony z trzech części Base64URL: nagłówka, ładunku i podpisu.
  • Nagłówek JWS powiadomienia serwera App Store zawiera łańcuch certyfikatów x5c złożony z trzech certyfikatów: podpisującego certyfikatu końcowego, certyfikatu pośredniego Apple z rozszerzeniem Apple Worldwide Developer Relations 1.2.840.113635.100.6.2.1 oraz certyfikatu głównego Apple.
  • App Store Server Library od Apple weryfikuje powiadomienia za pomocą SignedDataVerifier, który sprawdza łańcuch certyfikatów, identyfikator pakietu, environment, a w środowisku produkcyjnym także appAppleId, i może online sprawdzać unieważnienie certyfikatów.
  • Google Play Real-time developer notifications nie są podpisywane przez Google Play. Przy subskrypcji typu push Pub/Sub może dołączyć podpisany token OpenID Connect w nagłówku Authorization, a Twój serwer sprawdza jego podpis, odbiorcę (audience) i oświadczenia dotyczące adresu e-mail.
  • Według Google RTDN informuje jedynie o tym, że zmienił się stan zakupu, więc bezpieczną reakcją na każde powiadomienie o zwrocie jest potwierdzenie go w Google Play Developer API przed odebraniem dostępu.
  • Apple wysyła powiadomienia serwera App Store z podsieci 17.0.0.0/8, ale lista dozwolonych adresów IP jedynie zawęża krąg tych, którzy mogą dotrzeć do Twojego punktu końcowego. To podpis dowodzi, że wiadomość pochodzi od Apple.
  • Weryfikator, który błędnie odrzuca prawdziwe wiadomości, kosztuje tyle samo co taki, który przyjmuje fałszerstwa, ponieważ na odrzucony CONSUMPTION_REQUEST masz 12 godzin na odpowiedź, a na przegląd obciążenia zwrotnego w Google Play 24 godziny.

Każdy, kto pozna adres Twojego webhooka, może wysłać na niego zwrot. To niewygodny fakt stojący za każdym powiadomieniem serwera App Store i każdym Google Play Real-time developer notification: dopóki go nie zweryfikujesz, wiadomość jest tylko żądaniem HTTPS POST z odrobiną JSON w środku. Jeśli Twój serwer cofa subskrypcję, odbiera kredyty lub blokuje konto, bo w żądaniu było napisane REFUND, oddajesz tę władzę każdemu, kto potrafi napisać polecenie curl.

Oba sklepy dają Ci sposób na sprawdzenie. Apple podpisuje samo powiadomienie, więc powiadomienia serwera App Store możesz zweryfikować, mając jedynie certyfikat główny Apple. Google Play idzie inną drogą. Wiadomość nie jest podpisana, ale dostarczenie przez Pub/Sub może być, a Google i tak każe potwierdzać każdą zmianę przez swoje API. Poniżej opisujemy, czego dowodzi każde z tych rozwiązań i ile kosztuje pomyłka w jedną lub drugą stronę.

Co tak naprawdę podpisuje każdy ze sklepów

PytanieApp Store Server Notifications V2Google Play RTDN
Czy sama wiadomość jest podpisana?Tak, signedPayload to JWSNie, pole danych to JSON zakodowany w base64
Co dowodzi tożsamości nadawcyŁańcuch certyfikatów x5c do certyfikatu głównego AppleToken OIDC z Pub/Sub przy push lub Twój własny uwierzytelniony pull
Zagnieżdżone podpisane obiektysignedTransactionInfo i signedRenewalInfo, każdy jako osobny JWSBrak
Pola do dopasowania do Twojej aplikacjibundleId, appAppleId, environmentpackageName
Sieć źródłowa17.0.0.0/8, sandbox i produkcjaGoogle Cloud Pub/Sub
Potwierdzenie przed działaniemOpcjonalne, podpisane dane są dowodemWymagane, Google każe wywołać Developer API
TransportHTTPS, TLS 1.2 lub nowszyHTTPS push lub pull przez bibliotekę klienta

Jak weryfikować powiadomienia serwera App Store

Dokumentacja Apple opisuje signedPayload jako ciąg trzech komponentów zakodowanych w Base64URL i rozdzielonych kropkami: nagłówka, ładunku i podpisu, podpisany zgodnie ze specyfikacją JSON Web Signature. Zdekodowanie ładunku jest proste. Zaufanie mu wymaga czterech kontroli.

  • Odczytaj tablicę x5c ze zdekodowanego nagłówka. Apple dokumentuje kolejność: najpierw certyfikat z kluczem podpisującym, potem certyfikat pośredni Apple, a na końcu certyfikat główny Apple.
  • Zweryfikuj ten łańcuch względem certyfikatu głównego Apple pobranego samodzielnie z witryny PKI Apple, w praktyce Apple Root CA - G3. Nigdy nie ufaj certyfikatowi głównemu, który przyszedł w samej wiadomości, bo fałszerz może tam umieścić dowolny certyfikat.
  • Upewnij się, że certyfikat pośredni zawiera rozszerzenie Apple Worldwide Developer Relations 1.2.840.113635.100.6.2.1, a następnie zweryfikuj podpis JWS kluczem publicznym certyfikatu końcowego.
  • Porównaj zdekodowane dane ze swoją aplikacją: bundleId, appAppleId w środowisku produkcyjnym oraz environment. Prawidłowy podpis Apple na aplikacji innego dewelopera albo na zakupie z sandboxa, który trafił do Twojego produkcyjnego punktu końcowego, nadal nie oznacza Twojego zwrotu.

Następnie zrób to samo z zawartością. Obiekt data zawiera signedTransactionInfo i signedRenewalInfo, a każdy z nich jest osobnym JWS z własnym łańcuchem x5c. Procedura obsługi REFUND, która weryfikuje kopertę, ale odczytuje transakcję bez jej weryfikacji, zostawia lukę w samym środku.

Użyj biblioteki Apple zamiast pisać to samodzielnie

Apple udostępnia App Store Server Library dla Swift, Java, Python i Node. Jej SignedDataVerifier przyjmuje Twoje certyfikaty główne, flagę kontroli online, environment, identyfikator pakietu, a w środowisku produkcyjnym także appAppleId. Kod źródłowy dla Node pokazuje, co egzekwuje: dokładnie trzy certyfikaty w łańcuchu, rozszerzenie certyfikatu końcowego Apple 1.2.840.113635.100.6.11.1 i rozszerzenie certyfikatu pośredniego, daty ważności certyfikatów oraz zgodność identyfikatora pakietu, identyfikatora aplikacji i environment. Przy włączonych kontrolach online pyta też serwer OCSP, czy certyfikat końcowy i pośredni nie zostały unieważnione.

Lupa jubilerska trzymana nad papierowym certyfikatem z tłoczoną pieczęcią na drewnianym biurku, czyli taka dokładna kontrola, jakiej poddajesz wiadomość o zwrocie, zanim jej zaufasz

Czy lista dozwolonych adresów IP wystarczy?

Nie. Apple zaleca, aby w razie potrzeby stosowania listy dozwolonych adresów dodać podsieć 17.0.0.0/8, i dotyczy to zarówno sandboxa, jak i produkcji. To ogranicza szum. Nie dowodzi jednak, że wiadomość jest prawdziwa, i przestaje działać w chwili, gdy sieć Apple zmieni się w sposób, o którym nie wiesz. Prawdziwą bramką niech pozostanie sprawdzanie podpisu.

Jak weryfikować powiadomienia o zwrotach z Google Play

Google Play publikuje wiadomości RTDN w temacie Pub/Sub, który należy do Ciebie, a rolę Pub/Sub Publisher powinno w nim mieć wyłącznie konto usługi google-play-developer-notifications@system.gserviceaccount.com. Twoja subskrypcja dostarcza następnie wiadomości na jeden z dwóch sposobów, a każdy z nich ma własny dowód.

  • Subskrypcja typu pull: Twój serwer otwiera uwierzytelnione połączenie z Pub/Sub i pobiera wiadomości. Nie ma publicznego punktu końcowego, więc obca osoba nie ma dokąd wysłać żądania.
  • Subskrypcja typu push z włączonym uwierzytelnianiem: Pub/Sub podpisuje JSON Web Token i wysyła go w nagłówku Authorization jako token Bearer. Przewodnik Google każe zweryfikować podpis tokena i sprawdzić, czy jego oświadczenia email i audience odpowiadają skonfigurowanym przez Ciebie wartościom, a przykładowy kod wymaga dodatkowo, by email_verified miało wartość true. Token może mieć nawet godzinę.
  • Subskrypcja typu push bez uwierzytelniania: wszystko, co może dotrzeć do adresu URL, może wysłać wiadomość wyglądającą jak RTDN.

Dlaczego Google chce, abyś potwierdzał przez API

Nawet idealnie uwierzytelnione RTDN nie mówi wszystkiego. Przewodnik konfiguracji Google wprost stwierdza, że te powiadomienia informują tylko o zmianie stanu zakupu i że pełny status musisz uzyskać, wywołując Google Play Developer API. W przypadku voidedPurchaseNotification oznacza to odnalezienie zakupu w Voided Purchases API albo pobranie jego bieżącego stanu, zanim cokolwiek odbierzesz. Wywołanie API jest uwierzytelniane Twoim własnym kontem usługi, więc fałszerz nie podrobi jego odpowiedzi.

Ile kosztuje sfałszowany lub odrzucony zwrot

Sfałszowane powiadomienie o zwrocie, któremu zaufasz, kosztuje Cię płacącego klienta. Blokujesz kogoś, czyje pieniądze nadal masz, ta osoba zgłasza sprawę do supportu, a niektórzy pójdą do sklepu i poproszą o zwrot, który Twój system już udał, że przyznał. Sfałszowany zakup lub odnowienie kosztuje w drugą stronę: dostarczasz moc obliczeniową GPU, płatne wywołania zewnętrznych API, przestrzeń dyskową i wypłaty dla twórców w zamian za przychód, który nigdy nie istniał.

Odwrotny błąd jest cichszy i często większy. Weryfikator, który odrzuca prawdziwe wiadomości z powodu błędnego appAppleId, ustawienia sandboxa na produkcji albo nieaktualnego certyfikatu głównego, gubi dokładnie te dwa procesy zwrotów, w których liczą się Twoje dowody. Apple prosi o dane o wykorzystaniu w ciągu 12 godzin od CONSUMPTION_REQUEST. Google daje Ci 24 godziny na odpowiedź na przegląd obciążenia zwrotnego przez orders.reviewrefund, a w przypadku zamówień złożonych po 3 sierpnia 2026 przegrane obciążenie zwrotne w Google Play kosztuje Cię cenę zakupu pomniejszoną o opłatę serwisową Play, powiększoną o opłatę pobieraną przez bank kupującego.

BłądCo się dziejeIle to kosztuje
Przyjęty sfałszowany REFUNDPłacący klient traci dostępCzas supportu i prawdziwa prośba o zwrot, którą sam sprowokowałeś
Przyjęty sfałszowany zakupDarmowy dostęp do płatnych funkcjiMoc obliczeniowa, wywołania API, przestrzeń dyskowa i wypłaty bez przychodu
Odrzucony prawdziwy CONSUMPTION_REQUESTApple decyduje bez Twoich danychSprzedaż plus wszystko, co już wydano na jej realizację
Odrzucony prawdziwy przegląd obciążenia zwrotnegoGoogle decyduje bez Twoich dowodówCena zakupu i opłaty bankowe przy zamówieniach po 3 sierpnia 2026

Nie pozwól, by błąd weryfikacji zjadł termin

  • Zapisz surowe żądanie przed jego weryfikacją, aby odrzucona wiadomość nigdy nie przepadła na dobre.
  • Ustaw alert dla każdego nieudanego sprawdzenia. Jedna sfałszowana wiadomość to szum. Jeśli naraz odrzucane są wszystkie wiadomości, to błąd po Twojej stronie.
  • W Apple możesz ponownie przetworzyć to, co odrzuciłeś. Get Notification History zwraca oryginalny signedPayload z ostatnich 180 dni, więc popraw weryfikator i przepuść przez niego ponownie zapisane lub odzyskane ładunki.
  • W Google oczekujący przegląd obciążenia zwrotnego istnieje tylko w swoim powiadomieniu, więc źle skonfigurowane audience dla push oznacza przegapiony przegląd. Testuj to za pomocą Send Test Message w Play Console po każdej zmianie.

RefundHalt weryfikuje powiadomienia z obu sklepów, potwierdza zwroty przez API sklepów, zanim cokolwiek się zmieni, i odpowiada na CONSUMPTION_REQUEST oraz przeglądy obciążeń zwrotnych w wyznaczonych terminach. Dzięki temu fałszywa wiadomość nie kosztuje Cię klienta, a prawdziwa nie prześlizgnie się niezauważona.

Często zadawane pytania

Jak zweryfikować powiadomienie serwera App Store?
Zweryfikuj signedPayload jako JSON Web Signature. Odczytaj łańcuch certyfikatów x5c z jego nagłówka, zweryfikuj go względem certyfikatu głównego Apple pobranego z witryny PKI Apple, sprawdź podpis kluczem certyfikatu końcowego, a następnie upewnij się, że bundleId, appAppleId i environment pasują do Twojej aplikacji. App Store Server Library od Apple robi to wszystko w SignedDataVerifier.
Jakiego klucza używać do weryfikacji powiadomień serwera App Store?
Nie potrzebujesz klucza z App Store Connect. Klucz publiczny znajduje się w pierwszym certyfikacie łańcucha x5c w nagłówku JWS, a ufasz mu dopiero po zweryfikowaniu łańcucha aż do certyfikatu głównego Apple, który uzyskałeś samodzielnie. Twój klucz do zakupów w aplikacji służy do wywoływania API Apple, a nie do sprawdzania powiadomień.
Czy Google Play Real-time developer notifications są podpisane?
Nie, Google Play nie podpisuje samej wiadomości RTDN. Przy uwierzytelnionej subskrypcji typu push Pub/Sub wysyła w nagłówku Authorization podpisany token OpenID Connect, który weryfikujesz, a Google zaleca wywołanie Google Play Developer API po każdym powiadomieniu, aby uzyskać pełny status zakupu.
Czy mój serwer powinien zwracać błąd, gdy powiadomienie nie przejdzie weryfikacji?
Najpierw zapisz surowe żądanie, a potem zdecyduj. Apple ponawia powiadomienie w wersji 2 po odpowiedzi 40x lub 50x, po 1, 12, 24, 48 i 72 godzinach od poprzedniej próby. Jeśli przyczyną jest Twoja własna konfiguracja, Get Notification History pozwala odzyskać oryginalny signedPayload przez 180 dni i zweryfikować go ponownie po naprawie.
Czy nadal muszę weryfikować powiadomienia, jeśli dopuszczam tylko zakres IP Apple?
Tak. Apple prosi serwery z listą dozwolonych adresów o akceptowanie podsieci 17.0.0.0/8, co ogranicza, kto może się połączyć, ale nie dowodzi, że wiadomość jest prawdziwa. To podpis JWS wiąże powiadomienie z Apple i z Twoją aplikacją.

Źródła i materiały dodatkowe

RefundHalt

Autopilot zwrotów dla App Store i Google Play

Czytaj dalej

Kolejny wniosek o zwrot jest już w drodze.

Skonfiguruj RefundHalt w czasie potrzebnym na przeczytanie kolejnej wiadomości od pomocy technicznej o zwrocie, którego nie udało Ci się zakwestionować.