Z pewnością spotkałeś się z tym: skrypt działa, loguje się na stronie, wkłada produkt do koszyka, a potem następuje zmiana IP i nagle serwer odpowiada tak, jakbyś był tu pierwszy raz. Użytkownik jest wylogowany, koszyk pusty, token nieważny. Denerwujące? Oj tak. Ale ten problem ma konkretne rozwiązanie inżynieryjne i w tym przewodniku omówimy je od początku do końca.

Wprowadzenie: dlaczego po zmianie IP wylogowuje i koszyk pustoszeje

Mówmy szczerze: gdy sesja wylatuje po rotacji IP, pierwsza myśl to obwinianie samej zmiany adresu. Czyli: zmieniło się IP, serwer to zauważył i wszystko zresetował. Czasem tak jest. Ale znacznie częściej problem nie leży w samym IP, tylko w tym, jak skonstruowany jest Twój kod. Miesza on stan różnych sesji, gubi cookies, wysyła stare tokeny z nowego adresu. Nauczymy się, jak do tego nie dopuszczać.

Co czytelnik zyska na końcu

Po lekturze tego przewodnika będziesz potrafić kilka rzeczy. Po pierwsze, zrozumiesz, co naprawdę jest powiązane z IP po stronie serwera, a co jest mitem. Po drugie, wypracujesz ścisłą regułę dopasowania: jedna logiczna sesja równa się jeden zestaw cookies równa się jedno IP. Po trzecie, napiszesz działający kod w Pythonie i Node.js, który izoluje stan między różnymi proxy i nie miesza danych. Po czwarte, zapiszesz stan między uruchomieniami programu i będziesz wiedzieć, kiedy lepiej go wyrzucić.

Dla kogo jest ten przewodnik

Przewodnik jest przeznaczony dla średnio zaawansowanych. Piszesz już kod w Pythonie lub JavaScript, wiesz, co to zapytanie HTTP, i masz pojęcie, do czego służą proxy. Nie będziemy omawiać, jaki typ rotacji wybrać - od tego są osobne materiały. Tu zakładamy, że rotacja IP już odbywa się według Twoich zasad, i rozwiązujemy dokładnie jeden problem: jak nie tracić stanu podczas tej rotacji.

Co warto wiedzieć wcześniej

Warto rozumieć podstawy. Czym jest cookie - to mały fragment danych, który serwer prosi przeglądarkę lub klienta, aby zapamiętał i wysyłał z powrotem przy każdym zapytaniu. Czym jest sesja - to sposób, w jaki serwer rozpoznaje Cię między zapytaniami. Czym jest token - ciąg znaków potwierdzający Twoją tożsamość lub uprawnienie do działania. Jeśli te pojęcia są jeszcze niejasne, nie martw się: w sekcji podstawowych pojęć wyjaśnimy każde z nich prostym językiem.

Ile czasu to zajmie

Na przeczytanie i zrozumienie teorii wystarczy około czterdziestu minut. Na przeanalizowanie i uruchomienie kodu w Twoim języku - kolejna godzina lub półtorej. Pełne przyswojenie z eksperymentami na realnych zadaniach - dwie lub trzy godziny. Nie spiesz się. Lepiej powoli zrozumieć zasadę, niż szybko skopiować kod, który potem zepsuje się w niewyjaśniony sposób.

Przygotowanie wstępne: narzędzia i środowisko

Zanim napiszemy kod, uporządkujmy środowisko pracy. To zajmie trochę czasu, ale zaoszczędzi godziny debugowania później.

Wymagane narzędzia

  • Python w wersji 3.10 lub nowszej - jeśli pracujesz w Pythonie. W 2026 roku aktualne są wersje 3.12 i 3.13, ale wszystko opisane działa od wersji 3.10.
  • Node.js w wersji 20 LTS lub nowszej - jeśli pracujesz w JavaScript. Sprawdzi się też wersja 22 LTS.
  • Proxy z rotacją IP - powinieneś mieć już dostęp do puli adresów. Format połączenia zwykle wygląda tak: protokół, host, port, login i hasło.
  • Edytor kodu - wystarczy dowolny, na przykład darmowy edytor z podświetlaniem składni.
  • Terminal lub wiersz poleceń - do instalowania bibliotek i uruchamiania skryptów.

Wymagania systemowe

Wymagania są skromne. Poradzi sobie każdy nowoczesny komputer. Wystarczą cztery gigabajty pamięci RAM, ale jeśli planujesz wiele równoległych sesji, lepiej mieć osiem lub więcej. Ważniejsze jest stabilne połączenie internetowe, ponieważ przy utracie łączności cookies mogą nie zostać poprawnie zapisane.

Co należy zainstalować

Dla Pythona zainstaluj dwie biblioteki. Otwórz terminal i wykonaj polecenie instalacji pakietu requests oraz pakietu do obsługi proxy. Zapisuje się to tak: najpierw polecenie instalacji menedżera pakietów, potem nazwa requests. Do serializacji stanu przyda się standardowy moduł, nie trzeba go instalować osobno.

Dla Node.js zainstaluj trzy pakiety: axios do zapytań, tough-cookie do zarządzania magazynem cookies oraz https-proxy-agent do łączenia przez proxy. Wszystkie trzy instaluje się jednym poleceniem instalacji pakietów w Twoim projekcie.

Wskazówka: Utwórz osobny wirtualny folder dla projektu. W Pythonie to środowisko wirtualne, w Node.js - osobny katalog z plikiem opisu zależności. Dzięki temu nie wymieszasz bibliotek z różnych projektów i unikniesz konfliktów wersji.

Tworzenie kopii zapasowych

Jeśli już zapisujesz cookies do plików lub bazy danych, zrób kopię przed eksperymentami. Będziemy zmieniać logikę serializacji i istnieje ryzyko uszkodzenia istniejących danych. Po prostu skopiuj folder z zapisanymi stanami w miejsce oznaczone jako backup.

Sprawdzenie: Po instalacji upewnij się, że wszystko działa. Uruchom krótkie sprawdzenie wersji Pythona lub Node.js w terminalu. Powinieneś zobaczyć numer wersji bez błędów. Następnie spróbuj zaimportować zainstalowane biblioteki w trybie interaktywnym - jeśli import przebiega bez komunikatów, wszystko jest gotowe.

Podstawowe pojęcia: co jest powiązane z IP, a co to mit

To najważniejsza sekcja teoretyczna. Dopóki nie zrozumiesz, co naprawdę jest powiązane z IP, będziesz leczyć niewłaściwą chorobę. Przejdziemy przez typy danych po kolei.

Sesja cookie

Sesja cookie to sytuacja, w której serwer wydaje Ci identyfikator sesji w postaci cookie, a sam przechowuje stan u siebie. Na przykład cookie o nazwie sessionid z długim losowym ciągiem znaków. Serwer po tym ciągu znajduje Twój wpis w swojej pamięci. Czy ten mechanizm jest powiązany z IP? Sam w sobie - nie. Cookie działa niezależnie od adresu. Ale wiele serwisów dodaje dodatkową weryfikację: zapamiętują, z jakiego IP została utworzona sesja, a jeśli zapytanie z tym samym cookie przychodzi z innego adresu, uznają je za podejrzane. I tutaj następuje wylogowanie.

Token CSRF

Token CSRF to ochrona przed podrabianiem żądań. Serwer wydaje token, a Ty musisz odesłać go przy wysyłaniu formularza lub ważnej akcji. Ten token prawie nigdy nie jest powiązany z IP. Jest związany z sesją, a nie z adresem. Problem z nim pojawia się z innego powodu: jeśli zgubisz cookie sesji, token CSRF również staje się nieważny, ponieważ serwer nie może przypisać go do Twojej sesji. Czyli problem jest tutaj wtórny - wynika z utraty cookies.

JWT

JWT to token, który przenosi informacje w sobie i jest podpisany przez serwer. Klient przechowuje go i wysyła w nagłówku przy każdym żądaniu. Klasyczny JWT w ogóle nie jest powiązany z IP. Jest samowystarczalny: serwer sprawdza podpis i termin ważności, a adres go nie obchodzi. Ale zdarzają się implementacje, w których serwer dodatkowo przechowuje powiązanie tokena z IP po swojej stronie lub umieszcza adres wewnątrz tokena. W takich przypadkach zmiana IP psuje weryfikację. To nie jest cecha JWT, tylko decyzja konkretnego serwisu.

Sesja serwerowa

Sesja serwerowa to ogólna nazwa stanu, który serwer przechowuje u siebie i wiąże z Twoim identyfikatorem. Koszyk, historia przeglądania, status zalogowania - to wszystko często leży w sesji serwerowej. Powiązanie z IP zależy tutaj od ustawień serwisu. Niektóre serwisy dla bezpieczeństwa sztywno wiążą sesję z pierwszym IP. Inne są tolerancyjne na zmianę adresu. Zazwyczaj nie wiesz tego z góry, więc budujesz kod tak, jakby powiązanie istniało - to bezpieczna strategia.

Koszyk

Koszyk to szczególny przypadek sesji serwerowej albo cookie. W prostych sklepach koszyk jest przechowywany w cookie po stronie klienta. W bardziej złożonych - na serwerze, powiązany z sesją. Jeśli koszyk pustoszeje po zmianie IP, oznacza to, że był przypięty do sesji serwerowej, która sprawdza adres. Rozwiązanie jest takie samo: nie zmieniać IP w ramach jednej logicznej sesji albo ostrożnie zapisywać cały zestaw cookies.

Podsumowanie: gdzie IP naprawdę ma znaczenie

Złóżmy to w całość. Sam mechanizm HTTP cookies, CSRF i JWT nie jest powiązany z IP. Powiązanie pojawia się jako dodatkowa weryfikacja po stronie serwisu i nie masz na nią wpływu. Jedyne, czym zarządzasz, to dopasowanie między sesją, zestawem cookies i IP po Twojej stronie. Stąd wynika główna zasada tego przewodnika.

Sprawdzenie: Zweryfikuj swoje zrozumienie. Jeśli po zmianie IP sesja znika, ale po powrocie na stare IP wszystko się przywraca, oznacza to, że serwer sztywno sprawdza adres. Jeśli nie przywraca się nawet na starym IP - po prostu zgubiłeś cookies w kodzie. To dwie różne diagnozy z różnym leczeniem.

Krok 1: Formułujemy zasadę dopasowania

Cel etapu: utrwalić główną zasadę i zrozumieć, jak wyrazić ją w strukturze kodu.

Zasada brzmi prosto: jedna logiczna sesja równa się jeden zestaw cookies równa się jedno IP. Wyjaśnijmy, co to oznacza w praktyce.

  1. Logiczna sesja to łańcuch zapytań, które stanowią jedną ciągłą pracę: wszedłeś, zalogowałeś się, coś zrobiłeś, wyszedłeś. To wszystko jest jedną logiczną sesją.
  2. Jeden zestaw cookies to osobny magazyn cookies, który należy tylko do tej logicznej sesji i do nikogo innego.
  3. Jedno IP - w trakcie jednej logicznej sesji adres się nie zmienia. Jeśli rotacja jednak nastąpiła, logiczna sesja jest uznawana za zakończoną.

Jak to wyrazić w kodzie? Bardzo obrazowo: tworzymy obiekt-kontener, który zawiera w sobie zarówno magazyn cookies, jak i ustawienia proxy. Dopóki żyje ten obiekt, żyje logiczna sesja. Gdy przychodzi czas na zmianę IP, albo tworzymy nowy kontener, albo - jeśli serwis toleruje zmianę adresu - ostrożnie przenosimy cookies do nowego kontenera z nowym IP.

⚠️ Uwaga: Najczęstszy błąd architektoniczny to przechowywanie jednego wspólnego zestawu cookies i podstawianie do niego różnych proxy. To gwarantowanie psuje wszystko. Różne logiczne sesje zaczynają nadpisywać sobie cookies, a serwer otrzymuje sprzeczne dane. Nigdy tak nie rób.

Wskazówka: Myśl o logicznej sesji jak o człowieku. Jeden człowiek ma jedne dokumenty (cookies) i jeden dom (IP). Nie może być tak, żeby dwie osoby korzystały z tych samych dokumentów, ani żeby jedna osoba mieszkała jednocześnie w dwóch domach. Ta analogia uchroni Cię przed większością błędów.

Sprawdzenie: Narysuj na papierze swoją przyszłą strukturę. Powinieneś otrzymać kilka niezależnych bloków, każdy z własnym magazynem cookies i własnym proxy. Między blokami nie ma wspólnych danych. Jeśli tak jest - zrozumiałeś zasadę.

Krok 2: Praktyka w Pythonie - Session dla każdego proxy

Cel etapu: napisać działający kod, w którym każda logiczna sesja ma swój obiekt requests.Session, swój CookieJar i swoje proxy, odizolowane od siebie.

W bibliotece requests istnieje obiekt Session. Sam w sobie jest kontenerem: wewnątrz przechowuje magazyn cookies i potrafi stosować ustawienia do wszystkich zapytań. To idealna podstawa dla naszej logicznej sesji.

Podstawowa struktura

  1. Utwórz funkcję, która przyjmuje dane jednego proxy i zwraca gotowy obiekt Session.
  2. Wewnątrz funkcji utwórz nowy obiekt Session.
  3. Ustaw obiektowi konfigurację proxies - słownik z adresem proxy dla protokołów http i https.
  4. Zwróć obiekt. Teraz masz izolowany kontener.

Kod wygląda tak. Krok po kroku: importujemy requests. Definiujemy funkcję make_session, która przyjmuje ciąg znaków proxy_url. Wewnątrz piszemy s = requests.Session(). Następnie ustawiamy s.proxies na słownik, w którym klucz http wskazuje na proxy_url, a klucz https także wskazuje na proxy_url. Na końcu zwracamy s. To wszystko, funkcja jest gotowa.

Dlaczego to izoluje stan

Każde wywołanie make_session tworzy całkowicie nowy obiekt. Nowy obiekt ma własne wewnętrzne przechowywanie cookies, nazywane cookiejar. Cookies uzyskane przez jedną sesję fizycznie nie mogą trafić do innej sesji, ponieważ to różne obiekty w pamięci. Właśnie do tego dążyliśmy.

Korzystanie z sesji

  1. Pobierz obiekt sesji, wywołując funkcję z odpowiednim proxy.
  2. Wykonuj zapytania przez metody tego obiektu: s.get lub s.post.
  3. Cookies, które serwer wyśle w nagłówku Set-Cookie, automatycznie zapiszą się wewnątrz obiektu.
  4. Przy kolejnych zapytaniach przez ten sam obiekt cookies zostaną automatycznie odesłane.

Wskazówka: Nie twórz nowego Session dla każdego pojedynczego zapytania w ramach jednej logicznej sesji. Wtedy cookies nie będą się gromadzić. Twórz obiekt raz na całą logiczną sesję i używaj go do wszystkich zapytań tej sesji.

Izolacja między wątkami

Jeśli pracujesz w wielu wątkach, każdy wątek powinien mieć swój własny obiekt Session. Obiekt Session nie jest bezpieczny dla wątków. Oznacza to, że jeśli dwa wątki jednocześnie zapisują cookies do jednego obiektu, dane mogą zostać uszkodzone.

  1. Użyj mechanizmu lokalnych danych wątku. W Pythonie to obiekt threading.local.
  2. Na starcie każdego wątku utwórz dla niego osobną sesję i zapisz ją w lokalnym magazynie wątku.
  3. Wewnątrz wątku korzystaj tylko ze swojej sesji, nie dotykając cudzych.

W praktyce wygląda to tak: tworzymy globalny obiekt local = threading.local(). Na początku pracy wątku sprawdzamy, czy local ma atrybut session. Jeśli nie - tworzymy go wywołaniem make_session z proxy przypisanym do tego wątku. Dalej w wątku używamy local.session do wszystkich zapytań.

⚠️ Uwaga: Nigdy nie przekazuj jednego obiektu Session między wątkami jako wspólnego zasobu. Nawet jeśli wydaje się, że zapytania wykonują się po kolei, planista może przełączyć wątki w najmniej odpowiednim momencie, a otrzymasz wymieszane cookies. Każdemu wątkowi - własny obiekt.

Rotacja w logice

Kiedy rotacja IP już nastąpiła i potrzebujesz nowego adresu, postępuj tak. Zakończ bieżącą logiczną sesję: jeśli serwer sztywno wiąże sesję z IP, po prostu utwórz nowy obiekt Session z nowym proxy i zacznij od zera - zaloguj się ponownie. Jeśli serwer toleruje zmianę adresu, możesz przenieść cookies, o czym porozmawiamy w kroku dotyczącym przechowywania stanu.

Sprawdzenie: Uruchom dwie sesje z różnymi proxy, zaloguj się w każdej na testowym serwisie, który pokazuje Twój IP i cookies. Upewnij się, że każda sesja widzi swój IP i swój zestaw cookies. Jeśli dane się nie mieszają - izolacja działa poprawnie.

Krok 3: To samo w Node.js

Cel etapu: zbudować równoważną konstrukcję w JavaScript z użyciem axios, tough-cookie i agenta proxy.

W ekosystemie Node.js nie ma gotowego obiektu na poziomie Session, więc złożymy go z trzech części. Magazyn cookies weźmiemy z tough-cookie. Połączenie przez proxy zapewni agent. Zapytania będzie wykonywał axios.

Składamy kontener

  1. Zaimportuj klasę CookieJar z biblioteki tough-cookie.
  2. Zaimportuj funkcję tworzenia agenta proxy z biblioteki https-proxy-agent.
  3. Zaimportuj axios.
  4. Utwórz funkcję makeClient, która przyjmuje adres proxy i zwraca skonfigurowany obiekt.

Wewnątrz funkcji utwórz nową instancję magazynu: const jar = new CookieJar(). Utwórz agenta proxy, przekazując mu adres: const agent = new HttpsProxyAgent(...). Utwórz instancję axios z ustawieniami przez metodę axios.create(), przekazując do niej httpsAgent równe agent i httpAgent równe agent.

Podłączamy automatyczną obsługę cookies

Goły axios nie potrafi sam wrzucać cookies z odpowiedzi do magazynu i pobierać ich do zapytania. Są dwie ścieżki.

  1. Pierwsza ścieżka: użyć gotowego wrappera, który łączy axios i tough-cookie; instaluje się go jako osobny pakiet. Automatycznie czyta i zapisuje cookies przez przekazany magazyn jar.
  2. Druga ścieżka: zrobić to ręcznie przez przechwytywanie zapytań i odpowiedzi. Przed zapytaniem pobieramy ciąg cookies z magazynu dla odpowiedniego adresu i wstawiamy do nagłówka Cookie. Po odpowiedzi bierzemy nagłówek Set-Cookie i zapisujemy każdy cookie do magazynu.

Wskazówka: Na początek użyj gotowego wrappera - mniejsze ryzyko błędu. Ręczny wariant zostaw na sytuacje, gdy potrzebujesz precyzyjnie kontrolować proces, na przykład logować każdy cookie.

Izolacja między zadaniami równoległymi

W Node.js model jest inny - tutaj nie ma wątków, tylko zadania asynchroniczne w jednym wątku zdarzeń. Ale zasada jest ta sama: każda logiczna sesja ma swój oddzielny obiekt client z własnym jar i własnym agentem.

  1. Dla każdego równoległego zadania wywołuj makeClient osobno.
  2. Przechowuj klientów w tablicy lub mapie, gdzie kluczem jest identyfikator zadania.
  3. Nigdy nie używaj jednego jar dla kilku klientów jednocześnie.

⚠️ Uwaga: W kodzie asynchronicznym łatwo przypadkiem współdzielić jednego clienta między kilkoma łańcuchami promise. Wtedy cookies zaczną się mieszać między logicznymi sesjami. Zawsze sprawdzaj, czy każdy łańcuch używa własnego klienta, utworzonego osobnym wywołaniem makeClient.

Rotacja w Node.js

Logika jest identyczna jak w Pythonie. Gdy potrzebujesz nowego IP, a serwis wiąże sesję z adresem - utwórz nowego clienta z nowym proxy i nowym pustym jar, zaloguj się ponownie. Gdy serwis jest tolerancyjny - przenieś zawartość starego jar do nowego clienta z nowym agentem.

Sprawdzenie: Utwórz dwóch klientów z różnymi proxy. Wykonaj zapytania do testowego serwisu, który pokazuje IP i cookies. Upewnij się, że pierwszy klient widzi jeden IP i swoje cookies, drugi - inny IP i swoje. Nie powinno być żadnych przecięć.

Krok 4: Przechowywanie stanu między uruchomieniami

Cel etapu: nauczyć się zapisywać cookies na dysk i przywracać je przy następnym uruchomieniu programu, uwzględniając czas życia.

Często trzeba zatrzymać skrypt i uruchomić go później, nie tracąc autoryzacji. W tym celu cookies należy zserializować - zamienić na tekst i zapisać w pliku lub bazie danych.

Serializacja w Pythonie

Obiekt CookieJar z requests można zapisać na kilka sposobów. Najbardziej przenośny to zebranie cookies do prostego słownika i zapisanie w formacie JSON.

  1. Przejdź po wszystkich cookies obiektu sesji przez s.cookies.
  2. Dla każdego cookie zbierz jego nazwę, wartość, domenę, ścieżkę i termin ważności.
  3. Umieść to na liście słowników.
  4. Zapisz listę do pliku w formacie JSON.

Podczas przywracania zrób odwrotnie: odczytaj plik, przejdź po liście i dodaj każdy cookie do nowego obiektu sesji metodą ustawiania cookie z podaniem domeny i ścieżki.

Wskazówka: Przechowuj razem z cookies identyfikator proxy lub przynajmniej adnotację, do której logicznej sesji należą. Dzięki temu nie przywrócisz cudzych cookies z niewłaściwym IP i nie naruszysz zasady dopasowania.

Serializacja w Node.js

Biblioteka tough-cookie ma wbudowaną metodę serializacji. Obiekt jar ma asynchroniczną metodę, która zamienia cały magazyn na obiekt JSON. Odwrotna metoda przywraca jar z tego obiektu.

  1. Wywołaj metodę serializacji magazynu i otrzymaj obiekt.
  2. Zamień obiekt na ciąg znaków i zapisz do pliku.
  3. Przy uruchomieniu odczytaj plik, sparsuj ciąg znaków z powrotem na obiekt.
  4. Przywróć jar metodą deserializacji, przekazując obiekt.

To wygodniejsze niż w Pythonie, ponieważ tough-cookie sam przechowuje wszystkie potrzebne pola, w tym termin ważności i flagi bezpieczeństwa.

Czas życia cookies

Każde cookie ma termin ważności. Bywają cookies sesyjne - żyją do zamknięcia przeglądarki i nie mają jawnej daty. Bywają stałe - z konkretną datą wygaśnięcia. Zapisywać na dysku warto tylko stałe cookies, których termin jeszcze nie minął. Cookies sesyjne po restarcie zwykle są już nieważne na serwerze.

  1. Przed zapisaniem sprawdź datę wygaśnięcia każdego cookie.
  2. Odrzuć te, które już wygasły.
  3. Podczas przywracania ponownie sprawdź terminy i nie ładuj przeterminowanych.

Kiedy stan lepiej wyrzucić

Nie zawsze warto trzymać się zapisanych cookies. Czasami czysty start jest szybszy i bardziej niezawodny.

  • Jeśli od ostatniego uruchomienia minęło dużo czasu - sesja na serwerze na pewno wygasła, nie ma czego przywracać.
  • Jeśli serwer zwrócił błąd autoryzacji przy pierwszym zapytaniu z przywróconymi cookies - wyrzuć je i zaloguj się ponownie.
  • Jeśli nie jesteś pewien integralności pliku stanu - lepiej zacząć od zera, niż debugować dziwne zachowanie.

⚠️ Uwaga: Pliki z cookies i tokenami zawierają dane dostępowe. Przechowuj je w bezpiecznym miejscu, nie wrzucaj do wspólnego repozytorium, nie wysyłaj niezabezpieczonymi kanałami. Wyciek takiego pliku jest równoznaczny z wyciekiem dostępu do konta.

Sprawdzenie: Zapisz stan, całkowicie zamknij program, uruchom ponownie, przywróć stan i wykonaj zapytanie wymagające autoryzacji. Jeśli serwer odpowiada jak zalogowanemu użytkownikowi - zapisywanie działa. Jeśli wylogowuje - sprawdź terminy ważności oraz poprawność przywracania domeny i ścieżki.

Krok 5: Analiza częstych błędów architektonicznych

Cel etapu: szczegółowo przeanalizować trzy główne błędy, abyś rozpoznał je w swoim kodzie i nie dopuścił do nich.

Błąd pierwszy: wspólny CookieJar dla wszystkich proxy

To źródło wszelkiego zła. Programista tworzy jeden magazyn cookies i podstawia do niego różne proxy, myśląc, że oszczędzi. Co się dzieje: cookies z sesji na pierwszym IP trafiają do zapytania na drugim IP. Serwer widzi cookie utworzone pod innym adresem i albo resetuje sesję, albo uznaje zachowanie za podejrzane.

Rozwiązanie jest proste: każdemu proxy - własny magazyn cookies. Żadnych wyjątków. Już to uwzględniliśmy w krokach z kodem: osobny Session lub osobny client z osobnym jar dla każdej logicznej sesji.

Błąd drugi: wyścig przy równoległych zapytaniach

Wyścig to sytuacja, w której dwie operacje jednocześnie korzystają z tych samych danych i przeszkadzają sobie nawzajem. Jeśli dwa wątki zapisują do jednego CookieJar, jeden zapis może nadpisać drugi. Efekt: część cookies gubi się losowo, a błąd reprodukuje się co drugi raz, co jest koszmarem w debugowaniu.

  1. Daj każdemu wątkowi własną sesję przez lokalne dane wątku, jak opisaliśmy.
  2. W kodzie asynchronicznym nie współdziel jednego klienta między niezależnymi łańcuchami zadań.
  3. Jeśli z jakiegoś powodu obiekt jest jednak wspólny, użyj blokady, aby w danym momencie pracował z nim tylko jeden wątek.

Wskazówka: Najlepszy sposób na uniknięcie wyścigu to w ogóle nie mieć wspólnych zmiennych danych. Izolacja po logicznych sesjach rozwiązuje problem u źródła: jeśli dane nie są wspólne, wyścig nie może wystąpić.

Błąd trzeci: utrata Set-Cookie podczas przekierowań

Gdy serwer odpowiada przekierowaniem, często w tej samej odpowiedzi ustawia ważne cookies przez nagłówek Set-Cookie. Niektóre ustawienia klienta przy automatycznym podążaniu za przekierowaniem gubią te cookies - nie trafiają one do magazynu.

  1. Upewnij się, że Twój klient zapisuje cookies na każdym kroku łańcucha przekierowań, a nie tylko w końcowej odpowiedzi.
  2. W requests działa to domyślnie przy użyciu obiektu Session - cookies są zbierane po drodze. Sprawdź, czy nie wyłączyłeś podążania za przekierowaniami bez potrzeby.
  3. W axios przy ręcznej pracy z cookies przetwarzaj Set-Cookie w każdej pośredniej odpowiedzi. Jeśli używasz wrappera, sprawdź, czy przechwytuje przekierowania.

⚠️ Uwaga: Jeśli autoryzacja przechodzi, ale kolejne zapytanie wylogowuje, częstą przyczyną jest właśnie zgubiony podczas przekierowania cookie. Włącz logowanie wszystkich nagłówków Set-Cookie i sprawdź, czy wszystkie oczekiwane cookies dotarły do magazynu.

Sprawdzenie: Znajdź w docelowym serwisie akcję, która wywołuje przekierowanie, na przykład logowanie przez formularz. Prześledź łańcuch i porównaj cookies po każdym kroku. Wszystkie wydane cookies powinny znaleźć się w Twoim magazynie. Jeśli którejś brakuje - znalazłeś wyciek.

Krok 6: Składamy wszystko w jeden proces roboczy

Cel etapu: połączyć zdobytą wiedzę w jeden przewidywalny proces roboczy od startu do rotacji.

Masz już wszystkie elementy. Złóżmy je w łańcuch działań, który można powtarzać.

  1. Weź proxy ze swojej puli i utwórz dla niego izolowaną logiczną sesję - Session w Pythonie lub client w Node.js.
  2. Jeśli masz zapisany stan dla tej logicznej sesji i nie wygasł - przywróć cookies. W przeciwnym razie zaloguj się ponownie.
  3. Wykonuj potrzebne zapytania przez obiekt tej sesji. Cookies gromadzą się automatycznie.
  4. Okresowo zapisuj stan na dysk, aby nie stracić postępów w razie awarii.
  5. Gdy nadchodzi czas rotacji IP, zakończ logiczną sesję poprawnie.
  6. Jeśli serwis sztywno wiąże sesję z IP - zacznij nową logiczną sesję od zera pod nowym adresem.
  7. Jeśli serwis jest tolerancyjny - utwórz nowy kontener z nowym proxy i przenieś do niego cookies ze starego.

Wskazówka: Prowadź dziennik zdarzeń: kiedy utworzono sesję, z jakim IP, kiedy nastąpiła rotacja, czy było wylogowanie. Taki dziennik w pięć minut pokaże prawidłowość, której inaczej szukałbyś godzinami.

Sprawdzenie: Przeprowadź pełny cykl: utworzenie sesji, autoryzacja, kilka akcji, zapisanie, rotacja, kontynuacja. Upewnij się, że na każdym kroku stan zachowuje się przewidywalnie, a wylogowanie następuje tylko wtedy, gdy się tego spodziewasz.

Weryfikacja wyniku: finalna lista kontrolna

Przejdź przez tę listę. Jeśli wszystkie punkty są spełnione, Twój system działa poprawnie.

  • Każda logiczna sesja ma osobny obiekt-kontener ze swoim magazynem cookies.
  • Do każdego kontenera przypisane jest dokładnie jedno proxy przez cały czas życia sesji.
  • Nie ma ani jednego miejsca, w którym cookies jednej sesji mogłyby trafić do innej.
  • W kodzie wielowątkowym każdy wątek używa własnej sesji przez lokalne dane wątku.
  • W kodzie asynchronicznym każdy niezależny łańcuch ma własnego klienta.
  • Cookies są poprawnie zbierane na wszystkich etapach przekierowań.
  • Stan jest zapisywany i przywracany między uruchomieniami, z uwzględnieniem terminów ważności.
  • Przy zmianie IP logiczna sesja albo zaczyna się od nowa, albo cookies są przenoszone świadomie.
  • Pliki z cookies i tokenami są przechowywane bezpiecznie.

Jak to przetestować

  1. Znajdź testowy serwis, który pokazuje Twój bieżący IP i otrzymane cookies.
  2. Utwórz dwie sesje z różnymi proxy i upewnij się, że dane są w pełni izolowane.
  3. Zaloguj się, zapisz stan, uruchom program ponownie, przywróć - sprawdź, czy autoryzacja żyje.
  4. Zasymuluj rotację i obserwuj, jak zachowuje się sesja.

Wskaźniki sukcesu: dane różnych sesji nigdy się nie mieszają, wylogowanie następuje tylko przy sztywnej serwerowej przywiązaniu do IP, przywrócony stan działa, a wyścigi przy pracy równoległej nie występują.

Typowe błędy i rozwiązania

Problem: po zmianie IP użytkownik jest wylogowywany. Przyczyna: serwer sztywno wiąże sesję z adresem. Rozwiązanie: nie zmieniać IP w ramach jednej logicznej sesji, a gdy zmiana jest konieczna, rozpocząć sesję od nowa pod nowym adresem.

Problem: cookies różnych sesji się mieszają. Przyczyna: wspólny CookieJar dla kilku proxy. Rozwiązanie: dać każdej logicznej sesji osobny magazyn, nigdy nie współdzielić.

Problem: błąd pojawia się co drugi raz przy pracy równoległej. Przyczyna: wyścig przy zapisie do wspólnego obiektu z wielu wątków. Rozwiązanie: izolować sesje po wątkach przez lokalne dane wątku lub użyć blokady.

Problem: autoryzacja przechodzi, ale natychmiast znika. Przyczyna: utrata cookie podczas przekierowania. Rozwiązanie: sprawdzić zbieranie cookies na wszystkich etapach łańcucha przekierowań i włączyć logowanie Set-Cookie.

Problem: przywrócony stan nie działa. Przyczyna: zapisano przeterminowane lub sesyjne cookies albo nieprawidłowo podano domenę i ścieżkę. Rozwiązanie: zapisywać tylko ważne stałe cookies i przywracać z poprawną domeną i ścieżką.

Problem: token CSRF jest stale nieważny. Przyczyna: zgubiono cookie sesji, do której przypięty jest token. Rozwiązanie: najpierw przywrócić integralność cookies sesji, token automatycznie się podciągnie.

Problem: JWT przestaje działać po rotacji. Przyczyna: konkretny serwis przypiął token do IP po swojej stronie. Rozwiązanie: nie zmieniać IP w ciągu życia tokena albo uzyskać nowy token pod nowym adresem.

Dodatkowe możliwości i optymalizacja

Gdy podstawowy schemat działa, można go wzmocnić.

Pula gotowych sesji

Zamiast tworzyć sesję za każdym razem, trzymaj pulę wcześniej przygotowanych i zalogowanych logicznych sesji, każdą z własnym proxy. Bierz wolną sesję, używaj, zwracaj do puli. To przyspiesza pracę, bo autoryzacja nie powtarza się bez potrzeby.

Automatyczne sprawdzanie żywotności

Dodaj funkcję, która wykonuje lekkie zapytanie do serwisu i sprawdza, czy sesja żyje. Jeśli serwer odpowiada jak nieautoryzowanemu użytkownikowi - sesja jest oznaczana do ponownej autoryzacji. Dzięki temu wyłapiesz wygaśnięcie, zanim zepsuje ważną operację.

Wskazówka: Sprawdzanie żywotności wykonuj nie przed każdym zapytaniem, ale według harmonogramu lub po długich przerwach. Zbyt częste sprawdzanie tworzy dodatkowe obciążenie i nie przynosi korzyści.

Scentralizowane przechowywanie stanów

Dla dużych projektów zamiast plików używaj bazy danych jako magazynu cookies. Klucz - identyfikator logicznej sesji, wartość - zserializowany stan. Łatwiej to skalować i bezpieczniej przechowywać.

Metryki i obserwowalność

Zliczaj, ile razy następuje wylogowanie, ile sesji trzeba było utworzyć od nowa, jak często przywracanie kończy się sukcesem. Te liczby pokazują zdrowie Twojego systemu i podpowiadają, gdzie coś jest skonfigurowane nieoptymalnie.

FAQ: często zadawane pytania

Czy konieczne jest tworzenie nowego obiektu sesji przy każdej zmianie IP? Jeśli serwis sztywno sprawdza adres - tak, ponieważ stara sesja na nowym IP i tak nie zostanie przyjęta. Jeśli serwis jest tolerancyjny - można przenieść cookies do nowego kontenera z nowym proxy i kontynuować.

Czy można używać jednego proxy dla kilku logicznych sesji? Z punktu widzenia kodu można, ale każda logiczna sesja i tak powinna mieć swój oddzielny magazyn cookies. Wspólne mogą być tylko ustawienia połączenia, ale nie stan.

Dlaczego nie można po prostu trzymać wszystkich cookies w jednym miejscu i filtrować po domenie? Ponieważ problem nie leży w domenie, ale w powiązaniu z konkretną logiczną sesją i IP. Cookies jednej sesji w tej samej domenie nie powinny trafiać do innej sesji w tej samej domenie.

Jak sprawdzić, czy serwis wiąże sesję z IP? Przeprowadź eksperyment: zaloguj się na jednym IP, zmień adres i wykonaj zapytanie. Jeśli wylogowało - prawdopodobnie powiązanie istnieje. Wróć na stare IP: jeśli się przywróciło, oznacza to, że serwer pamięta pierwszy adres.

Co zrobić z sesyjnymi cookies przy zapisie na dysk? Zwykle nie ma sensu ich zapisywać, ponieważ serwer uznaje je za nieważne po zerwaniu połączenia. Zapisuj stałe cookies z aktywnym terminem ważności.

Co zrobić, jeśli biblioteka sama nie zapisuje cookies podczas przekierowania? Przetwarzaj nagłówek Set-Cookie ręcznie w każdej pośredniej odpowiedzi łańcucha przekierowań i wkładaj cookies do swojego magazynu.

Czy potrzebna jest blokada, jeśli każdy wątek ma własną sesję? Nie. Jeśli dane nie są wspólne, wyścig nie może wystąpić, a blokada nie jest potrzebna. Blokada jest wymagana tylko przy wymuszonym współdzieleniu jednego obiektu.

Jak długo można przechowywać stan do przywrócenia? Dokładnie tak długo, jak serwer uważa sesję za żywą. Dokładny czas zależy od serwisu. Bardziej praktyczne jest sprawdzanie żywotności zapytaniem niż zgadywanie po czasie.

Co jest ważniejsze - zapisać cookies czy zapisać token? To zależy od mechanizmu autoryzacji serwisu. Czasem wystarczy token, czasem potrzebny jest pełny zestaw cookies. Bezpieczniej zapisywać cały stan, wtedy niczego nie pominiesz.

Czy można przenosić cookies między Pythonem i Node.js? Tak, jeśli zapisujesz je w wspólnym neutralnym formacie, takim jak JSON z polami nazwy, wartości, domeny, ścieżki i terminu. Wtedy każdy z tych systemów będzie mógł je odczytać.

Podsumowanie

Podsumujmy to, czego się nauczyłeś. Zrozumiałeś, że po zmianie IP wylogowuje nie z powodu samej zmiany, ale z powodu serwerowych kontroli i błędów w Twojej architekturze. Dowiedziałeś się, że cookies, CSRF i JWT same w sobie nie są powiązane z adresem, a powiązanie dodaje konkretny serwis. Przyswoiłeś główną zasadę: jedna logiczna sesja równa się jeden zestaw cookies równa się jedno IP.

Następnie napisałeś działający kod. W Pythonie - przez osobny obiekt Session z własnym CookieJar dla każdego proxy i izolacją między wątkami. W Node.js - przez połączenie axios, tough-cookie i agenta proxy z osobnym klientem dla każdej logicznej sesji. Nauczyłeś się zapisywać stan między uruchomieniami, uwzględniać terminy ważności cookies i rozumieć, kiedy stan lepiej wyrzucić.

Przeanalizowałeś trzy podstępne błędy: wspólny CookieJar, wyścig przy pracy równoległej i utratę Set-Cookie podczas przekierowań. Teraz masz listę kontrolną przed wdrożeniem, która nie pozwoli wypuścić surowego rozwiązania.

Co robić dalej

Zacznij od małych kroków. Weź jeden rzeczywisty scenariusz, zaimplementuj dla niego izolowaną logiczną sesję i upewnij się, że stan nie jest tracony. Potem dodaj zapisywanie na dysk. Potem skaluj na kilka sesji. Posuwaj się krok po kroku, weryfikując wynik na każdym etapie.

Gdzie się rozwijać

Następnie warto zagłębić się w obserwowalność: skonfigurować metryki żywotności sesji i logowanie zdarzeń. Potem nauczyć się świadomie przenosić stan, gdy serwis toleruje zmianę adresu. Na koniec zbudować pulę gotowych sesji dla przyspieszenia pracy. Każdy z tych kroków czyni Twój system bardziej stabilnym i przewidywalnym. Dasz radę - zasadę już rozumiesz, reszta to kwestia praktyki.