Używanie proxy w Swift z URLSession — przewodnik dla programistów iOS i macOS

Kompletny przewodnik po konfiguracji proxy w Swift z URLSession: HTTP/HTTPS, SOCKS5, autoryzacja, geo-targeting, async/await i wskazówki produkcyjne.

Using Proxies in Swift: A Code-First Guide to URLSession, SOCKS5 & Residential IPs
W tym artykule

Używanie proxy w Swift z URLSession — podstawy

Konfiguracja proxy w Swift przez URLSession to zadanie, które wielu programistów iOS i macOS odkłada na później — dokumentacja Apple jest rozproszona, a klucze CFNetwork trudne do znalezienia. Jeśli budujesz aplikację, która musi pobierać dane z API ograniczonych regionalnie, monitorować ceny lub scrapować publiczne strony, Swift proxy staje się niezbędny. W tym przewodniku pokazuję krok po kroku, jak skonfigurować URLSessionConfiguration.connectionProxyDictionary, jak obsłużyć autoryzację i geo-targeting, jak używać SOCKS5 oraz jak pisać wydajny kod async/await z obsługą błędów.

Dlaczego proxy w URLSession to problem

URLSession domyślnie używa ustawień systemowych (System Configuration), co oznacza, że jeśli użytkownik ma ustawione proxy w Wi-Fi, URLSession je zastosuje. Programowa konfiguracja proxy wymaga ustawienia connectionProxyDictionary na obiekcie URLSessionConfiguration przed utworzeniem sesji. Słownik ten używa kluczy z frameworka CFNetwork, zdefiniowanych w dokumentacji CFNetwork Apple. Problem polega na tym, że te klucze nie są bezpośrednio widoczne w Swift — trzeba je przekonwertować z CFString na String.

Dodatkowo URLSession ma ograniczoną obsługę proxy authentication — klucze kCFProxyUsernameKey i kCFProxyPasswordKeynielidalne w wielu wersjach iOS/macOS (patrz dokumentacja URLSessionConfiguration.connectionProxyDictionary), co zmusza do ręcznego ustawiania nagłówka Proxy-Authorization lub implementacji delegata urlSession(_:didReceive:completionHandler:).

Konfiguracja HTTP/HTTPS proxy w URLSession

Zacznijmy od podstawowej konfiguracji proxy HTTP i HTTPS, kierującego ruch przez bramę ProxyHat gate.proxyhat.com na porcie 8080. Musimy ustawić osobne klucze dla HTTP i HTTPS, ponieważ URLSession traktuje je niezależnie.

import Foundation

func createProxySession(username: String, password: String) -> URLSession {
    let config = URLSessionConfiguration.ephemeral

    // Klucze CFNetwork — konwertujemy z CFString
    let kHTTPEnable = kCFNetworkProxiesHTTPEnable as String
    let kHTTPProxy = kCFNetworkProxiesHTTPProxy as String
    let kHTTPPort = kCFNetworkProxiesHTTPPort as String
    let kHTTPSEnable = kCFNetworkProxiesHTTPSEnable as String
    let kHTTPSProxy = kCFNetworkProxiesHTTPSProxy as String
    let kHTTPSPort = kCFNetworkProxiesHTTPSPort as String

    config.connectionProxyDictionary = [
        kHTTPEnable: true,
        kHTTPProxy: "gate.proxyhat.com",
        kHTTPPort: 8080,
        kHTTPSEnable: true,
        kHTTPSProxy: "gate.proxyhat.com",
        kHTTPSPort: 8080
    ]

    // Proxy-Authorization header — bo kCFProxyUsernameKey/PasswordKey
    // są nielidalne w URLSession
    let token = "\(username):\(password)"
    let base64 = Data(token.utf8).base64EncodedString()
    config.httpAdditionalHeaders = [
        "Proxy-Authorization": "Basic \(base64)"
    ]

    return URLSession(configuration: config)
}

// Użycie
let session = createProxySession(
    username: "user-country-US-city-newyork-session-abc123",
    password: "twoje_haslo"
)
let url = URL(string: "https://httpbin.org/ip")!
let task = session.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Błąd: \(error)")
        return
    }
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Zwróć uwagę na URLSessionConfiguration.ephemeral — używamy go zamiast .default, aby uniknąć wycieków danych do pamięci podręcznej i plików cookie, które mogą ujawnić prawdziwe IP użytkownika. httpAdditionalHeaders ustawia nagłówek Proxy-Authorization globalnie dla całej sesji, co jest najprostszym sposobem autoryzacji.

Autoryzacja i geo-targeting — Proxy-Authorization vs delegat 407

Geo-targeting w ProxyHat odbywa się przez zakodowanie parametrów w nazwie użytkownika, np. user-country-US-city-newyork-session-abc123. To oznacza, że pełny token Basic Auth zawiera znaki specjalne, które muszą być poprawnie zakodowane w Base64.

Powyższe podejście z httpAdditionalHeaders działa w większości przypadków, ale niektóre serwery proxy mogą najpierw odrzucić żądanie z kodem 407 Proxy Authentication Required, zamiast zaakceptować nagłówek uprzedzający. Wtedy musisz zaimplementować delegata urlSession(_:didReceive:completionHandler:):

import Foundation

class ProxyAuthDelegate: NSObject, URLSessionDelegate {
    let username: String
    let password: String

    init(username: String, password: String) {
        self.username = username
        self.password = password
    }

    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        // Sprawdź, czy to wyzwanie proxy (nie serwera)
        if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodHTTPProxy ||
           challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodHTTPSProxy {

            let credential = URLCredential(
                user: username,
                password: password,
                persistence: .forSession
            )
            completionHandler(.useCredential, credential)
        } else {
            // Pozostałe wyzwania (TLS itp.) — domyślne zachowanie
            completionHandler(.performDefaultHandling, nil)
        }
    }
}

// Użycie z geo-targetingiem
let delegate = ProxyAuthDelegate(
    username: "user-country-DE-city-berlin-session-sess42",
    password: "twoje_haslo"
)

let config = URLSessionConfiguration.ephemeral
config.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable as String: true,
    kCFNetworkProxiesHTTPProxy as String: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPPort as String: 8080,
    kCFNetworkProxiesHTTPSEnable as String: true,
    kCFNetworkProxiesHTTPSProxy as String: "gate.proxyhat.com",
    kCFNetworkProxiesHTTPSPort as String: 8080
]

let session = URLSession(configuration: config, delegate: delegate, delegateQueue: nil)

Wybór między nagłówkiem Proxy-Authorization a delegatem zależy od Twojego przypadku użycia. Nagłówek jest prostszy i działa z URLSession.shared, ale nie obsługuje ponownego wyzwania. Delegat jest bardziej niezawodny, ale wymaga utworzenia dedykowanej sesji. W produkcji zalecam oba podejścia jednocześnie — nagłówek jako domyślne, delegat jako fallback.

SOCKS5 proxy w URLSession

ProxyHat obsługuje również SOCKS5 na porcie 1080. Konfiguracja SOCKS5 w URLSession używa kluczy kCFStreamPropertySOCKSProxy*, które są mniej udokumentowane, ale działają poprawnie:

import Foundation

func createSOCKS5Session(username: String, password: String) -> URLSession {
    let config = URLSessionConfiguration.ephemeral

    let kProxyEnable = kCFNetworkProxiesSOCKSEnable as String
    let kProxyHost = kCFStreamPropertySOCKSProxyHost as String
    let kProxyPort = kCFStreamPropertySOCKSProxyPort as String
    let kProxyVersion = kCFStreamPropertySOCKSVersion as String
    let kProxyUser = kCFStreamPropertySOCKSProxyUser as String
    let kProxyPass = kCFStreamPropertySOCKSProxyPassword as String

    config.connectionProxyDictionary = [
        kProxyEnable: true,
        kProxyHost: "gate.proxyhat.com",
        kProxyPort: 1080,
        kProxyVersion: kCFStreamSocketSOCKSVersion5 as String,
        kProxyUser: username,
        kProxyPass: password
    ]

    return URLSession(configuration: config)
}

let socksSession = createSOCKS5Session(
    username: "user-country-GB-session-task99",
    password: "twoje_haslo"
)

SOCKS5 w URLSession obsługuje natywnie autoryzację username/password przez klucze kCFStreamPropertySOCKSProxyUser i kCFStreamPropertySOCKSProxyPassword — w przeciwieństwie do HTTP proxy, gdzie te klucze są nielidalne. Jeśli więc potrzebujesz prostszej autoryzacji bez nagłówków, SOCKS5 może być lepszym wyborem.

Dlaczego proxy rezydencjalne są potrzebne — Swift web scraping w praktyce

Wiele API i stron web blokuje adresy IP z centrów danych (datacenter). Przykładowo, Cloudflare i Akamai mają listy znanych zakresów IP centrów danych i odrzucają żądania z tych adresów z kodem 403 lub wstawiają wyzwanie CAPTCHA. Proxy rezydencjalne pochodzą z prawdziwych urządzeń domowych przydzielonych przez ISP, co sprawia, że ruch wygląda jak organiczny.

Typowe scenariusze, w których potrzebujesz proxy rezydencjalnych w Swift:

  • Scraping SERP — Google ogranicza liczbę zapytań z jednego IP do około 100 zapytań/dzień przed wyświetleniem CAPTCHA.
  • Monitoring cen e-commerce — sklepy jak Amazon i Walmart blokują podejrzane wzorce ruchu z datacenter.
  • Treści regionalnie ograniczone — API streamingowe i sportowe często sprawdzają geolokalizację IP.
  • Testowanie aplikacji — QA zespoły potrzebują symulować ruch z różnych krajów.

Oto kompletny przykład async/await z URLSession.shared.data(for:), dekodowaniem Codable i TaskGroup dla współbieżności:

import Foundation

// Model odpowiedzi z httpbin.org/ip
struct IPResponse: Codable {
    let origin: String
}

// Konfiguracja sesji z proxy
func makeProxySession(country: String, session: String) -> URLSession {
    let config = URLSessionConfiguration.ephemeral
    config.connectionProxyDictionary = [
        kCFNetworkProxiesHTTPEnable as String: true,
        kCFNetworkProxiesHTTPProxy as String: "gate.proxyhat.com",
        kCFNetworkProxiesHTTPPort as String: 8080,
        kCFNetworkProxiesHTTPSEnable as String: true,
        kCFNetworkProxiesHTTPSProxy as String: "gate.proxyhat.com",
        kCFNetworkProxiesHTTPSPort as String: 8080
    ]

    let username = "user-country-\(country)-session-\(session)"
    let token = "\(username):twoje_haslo"
    let base64 = Data(token.utf8).base64EncodedString()
    config.httpAdditionalHeaders = ["Proxy-Authorization": "Basic \(base64)"]
    config.timeoutIntervalForRequest = 15
    config.timeoutIntervalForResource = 30

    return URLSession(configuration: config)
}

// Funkcja pobierająca IP przez proxy
func fetchIP(country: String, sessionID: String) async throws -> String {
    let session = makeProxySession(country: country, session: sessionID)
    let url = URL(string: "https://httpbin.org/ip")!
    let (data, response) = try await session.data(for: URLRequest(url: url))

    guard let httpResp = response as? HTTPURLResponse,
          httpResp.statusCode == 200 else {
        throw URLError(.badServerResponse)
    }

    let decoded = try JSONDecoder().decode(IPResponse.self, from: data)
    return decoded.origin
}

// Współbieżne pobieranie z wielu krajów
func fetchMultipleCountries() async {
    let countries = ["US", "DE", "GB", "JP", "BR"]

    do {
        let results = try await withThrowingTaskGroup(of: (String, String).self) { group in
            for country in countries {
                group.addTask {
                    let ip = try await fetchIP(country: country, sessionID: "batch-\(country)")
                    return (country, ip)
                }
            }

            var collected: [(String, String)] = []
            for try await result in group {
                collected.append(result)
            }
            return collected
        }

        for (country, ip) in results.sorted(by: { $0.0 < $1.0 }) {
            print("\(country): \(ip)")
        }
    } catch {
        print("Błąd współbieżny: \(error)")
    }
}

// Uruchomienie
Task { await fetchMultipleCountries() }

Powyższy kod tworzy osobną sesję URLSession dla każdego kraju z unikalnym sessionID, co daje sticky session — wszystkie żądania w ramach jednej sesji używają tego samego IP. TaskGroup uruchamia zapytania współbieżnie, a URLSession zarządza pulą połączeń wewnętrznie. Zwróć uwagę, że tworzenie nowej URLSession dla każdego zadania nie jest idealne — w produkcji powinieneś buforować sesje.

Wskazówki produkcyjne — TLS, retry, ATS i prywatność

Delegat TLS i walidacja certyfikatów

W niektórych przypadkach (np. corporate MITM proxy) musisz obsłużyć niestandardowe certyfikaty. Użyj URLSessionDelegate do walidacji TLS:

import Foundation

class TLSPinningDelegate: NSObject, URLSessionDelegate {
    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            guard let trust = challenge.protectionSpace.serverTrust else {
                completionHandler(.cancelAuthenticationChallenge, nil)
                return
            }

            // Walidacja standardowa + opcjonalne pinning
            var error: CFError?
            let isValid = SecTrustEvaluateWithError(trust, &error)

            if isValid {
                completionHandler(.useCredential, URLCredential(trust: trust))
            } else {
                print("TLS validation failed: \(error?.localizedDescription ?? "unknown")")
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        } else {
            completionHandler(.performDefaultHandling, nil)
        }
    }
}

Retry z exponential backoff

Zapytania przez proxy mogą zawodzić z powodu timeoutów, rate limitów (HTTP 429) lub tymczasowych błędów sieci. Implementacja retry z exponential backoff jest kluczowa:

import Foundation

enum ProxyError: Error {
    case maxRetriesExceeded
    case rateLimited(retryAfter: TimeInterval)
}

func fetchWithRetry(
    url: URL,
    session: URLSession,
    maxRetries: Int = 3,
    baseDelay: TimeInterval = 1.0
) async throws -> Data {
    var attempt = 0

    while attempt < maxRetries {
        do {
            let (data, response) = try await session.data(for: URLRequest(url: url))

            if let httpResp = response as? HTTPURLResponse {
                if httpResp.statusCode == 429 {
                    let retryAfter = httpResp.value(forHTTPHeaderField: "Retry-After")
                    let delay = TimeInterval(retryAfter ?? "5") ?? 5
                    try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
                    attempt += 1
                    continue
                }

                if httpResp.statusCode == 200 {
                    return data
                }

                if (500...599).contains(httpResp.statusCode) {
                    let delay = baseDelay * pow(2.0, Double(attempt))
                    try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
                    attempt += 1
                    continue
                }

                return data // inne kody — zwróć dane
            }
        } catch let error as URLError {
            let delay = baseDelay * pow(2.0, Double(attempt))
            print("Próba \(attempt + 1) błąd: \(error.code.rawValue) — retry za \(delay)s")
            try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
            attempt += 1
            continue
        }
    }

    throw ProxyError.maxRetriesExceeded
}

App Transport Security (ATS)

Apple wymaga TLS 1.2+ dla wszystkich połączeń przez App Transport Security. Proxy HTTP (nie HTTPS) między aplikacją a serwerem docelowym jest w pełni kompatybilne z ATS, ponieważ proxy tylko przekazuje tunelowane żądanie TLS — nie dekoduje go. Nie musisz wyłączać ATS, jeśli używasz proxy HTTP dla ruchu HTTPS do celu. Jeśli jednak próbujesz połączyć się z celem HTTP (nie HTTPS), musisz dodać wyjątek ATS w Info.plist.

Prywatność na urządzeniu

  • Używaj URLSessionConfiguration.ephemeral, aby uniknąć zapisywania ciasteczek i pamięci podręcznej na dysku.
  • Nie loguj zawartości nagłówka Proxy-Authorization — zawiera on poświadczenia w Base64.
  • Dodaj NSPrivacyAccessedAPICategoryUserDefaults do Privacy Manifest, jeśli przechowujesz konfigurację proxy w UserDefaults.
  • Aplikacje na iOS 17+ muszą deklarować powody używania API sieciowych w Privacy Manifest.

Konfiguracja ProxyHat — gotowe w 5 minut

ProxyHat udostępnia bramę gate.proxyhat.com na porcie 8080 (HTTP) i 1080 (SOCKS5). Wszystkie parametry geo-targetingu i sesji kodujesz w nazwie użytkownika:

Parametr Format w username Przykład
Kraj country-XX user-country-US
Miasto city-name user-country-US-city-newyork
Sticky session session-ID user-session-abc123
Kombinacja wszystkie razem user-country-DE-city-berlin-session-s1

Sprawdź ceny ProxyHat oraz dostępne lokalizacje. ProxyHat udostępnia również SDK dla Python i Node.js, które odzwierciedlają tę samą bramę — przydatne, jeśli Twój backend nie jest w Swift. Pełną dokumentację API znajdziesz na docs.proxyhat.com.

Jeśli interesuje Cię scraping wyników wyszukiwania, zobacz nasz przewodnik SERP tracking. Do ogólnego scrapingu stron polecamy web scraping use case.

Etyka i prawo — co musisz wiedzieć

Używanie proxy do pobierania publicznych danych jest legalne w większości jurysdykcji, ale istnieją granice:

  • USA — CFAA (Computer Fraud and Abuse Act): scraping publicznych danych nie narusza CFAA według orzeczenia Van Buren v. United States (2021), ale omijanie technicznych barier (CAPTCHA, rate limiting) może być problematyczne. Zobacz stanowisko FTC w sprawie scraping.
  • EU — GDPR: jeśli scrapujesz dane osobowe (np. profile użytkowników), musisz mieć podstawę prawną. Pobieranie publicznych danych nieosobowych nie podlega GDPR.
  • App Store Guidelines: Apple wymaga, aby aplikacje nie zbierały danych bez zgody użytkownika i nie naruszały ToS stron trzecich. Scraping w aplikacji klienckiej może naruszyć punkt 5.2.2 guidelines.
  • Zawsze sprawdzaj robots.txt i ToS przed scrapingiem.

Złota zasada: jeśli istnieje oficjalne API, użyj go najpierw. Proxy są dla przypadków, gdy API nie istnieje, jest zbyt ograniczone lub nie pokrywa potrzebnych regionów.

Kluczowe wnioski

Kluczowe wnioski:

  • Używaj connectionProxyDictionary z kluczami kCFNetworkProxiesHTTP* i kCFNetworkProxiesHTTPS* do konfiguracji proxy HTTP/HTTPS w URLSession.
  • Klucze kCFProxyUsernameKey/kCFProxyPasswordKey są nielidalne w URLSession — używaj nagłówka Proxy-Authorization: Basic lub delegata urlSession(_:didReceive:).
  • SOCKS5 na porcie 1080 obsługuje natywnie autoryzację username/password przez kCFStreamPropertySOCKSProxyUser/Password.
  • Geo-targeting i sticky sessions koduj w nazwie użytkownika: user-country-US-city-newyork-session-abc123.
  • Implementuj retry z exponential backoff dla HTTP 429 i 5xx.
  • Proxy HTTP nie narusza ATS — TLS jest tunelowane.
  • Preferuj oficjalne API; używaj proxy tylko do publicznych danych i zgodnie z prawem.

FAQ

Czym jest używanie proxy w Swift?

Używanie proxy w Swift polega na skonfigurowaniu URLSessionConfiguration.connectionProxyDictionary z kluczami CFNetwork, aby kierować ruch HTTP/HTTPS lub SOCKS5 przez serwer proxy — np. bramę ProxyHat gate.proxyhat.com:8080. Pozwala to na ukrywanie IP, geo-targeting i omijanie blokad regionalnych w aplikacjach iOS i macOS.

Dlaczego używanie proxy w Swift jest ważne?

Proxy są kluczowe, gdy endpointy API blokują adresy IP z centrów danych (datacenter), nakładają limity zapytań lub ograniczają treści regionalnie. Bez proxy rezydencjalnego aplikacja iOS może otrzymywać kody 403/429 lub CAPTCHA. Proxy rezydencjalne pochodzą z prawdziwych ISP, co sprawia, że ruch wygląda organicznie i omija te blokady.

Który typ proxy najlepiej działa w Swift?

Proxy rezydencjalne (residential) są najlepsze do scrapingu i dostępu do treści regionalnie ograniczonych, ponieważ ich adresy IP pochodzą z ISP i nie są na listach blokad. Proxy datacenter są szybsze i tańsze, ale łatwo wykrywalne. SOCKS5 jest preferowany, gdy potrzebujesz natywnej autoryzacji username/password bez nagłówków. Proxy mobilne są najtrudniejsze do zablokowania, ale najdroższe.

Jak unikać blokad przy używaniu proxy w Swift?

Implementuj rotację sesji (zmienne sessionID), używaj sticky sessions tylko gdy potrzebujesz spójności IP, dodaj retry z exponential backoff dla HTTP 429/5xx, ogranicz współbieżność do 5–10 jednoczesnych żądań na sesję, ustaw realistyczne nagłówki User-Agent i opóźnienia między zapytaniami (np. 200–500ms). Konfiguruj timeoutIntervalForRequest na 15s, aby unikać zawieszeń.

Czy proxy HTTP w URLSession narusza App Transport Security?

Nie. Proxy HTTP działa jako tunel dla ruchu HTTPS — sesja TLS jest nawiązywana między aplikacją a serwerem docelowym, a proxy tylko przekazuje zaszyfrowane pakiety. ATS wymaga TLS 1.2+ dla połączenia końcowego, a nie dla proxy. Nie musisz wyłączać ATS, chyba że łączysz się z celem HTTP (nie HTTPS).

Często zadawane pytania

Czym jest używanie proxy w Swift?

Używanie proxy w Swift polega na skonfigurowaniu URLSessionConfiguration.connectionProxyDictionary z kluczami CFNetwork, aby kierować ruch HTTP/HTTPS lub SOCKS5 przez serwer proxy — np. bramę ProxyHat gate.proxyhat.com:8080. Pozwala to na ukrywanie IP, geo-targeting i omijanie blokad regionalnych w aplikacjach iOS i macOS.

Dlaczego używanie proxy w Swift jest ważne?

Proxy są kluczowe, gdy endpointy API blokują adresy IP z centrów danych (datacenter), nakładają limity zapytań lub ograniczają treści regionalnie. Bez proxy rezydencjalnego aplikacja iOS może otrzymywać kody 403/429 lub CAPTCHA. Proxy rezydencjalne pochodzą z prawdziwych ISP, co sprawia, że ruch wygląda organicznie i omija te blokady.

Który typ proxy najlepiej działa w Swift?

Proxy rezydencjalne (residential) są najlepsze do scrapingu i dostępu do treści regionalnie ograniczonych, ponieważ ich adresy IP pochodzą z ISP i nie są na listach blokad. Proxy datacenter są szybsze i tańsze, ale łatwo wykrywalne. SOCKS5 jest preferowany, gdy potrzebujesz natywnej autoryzacji username/password bez nagłówków. Proxy mobilne są najtrudniejsze do zablokowania, ale najdroższe.

Jak unikać blokad przy używaniu proxy w Swift?

Implementuj rotację sesji (zmienne sessionID), używaj sticky sessions tylko gdy potrzebujesz spójności IP, dodaj retry z exponential backoff dla HTTP 429/5xx, ogranicz współbieżność do 5–10 jednoczesnych żądań na sesję, ustaw realistyczne nagłówki User-Agent i opóźnienia między zapytaniami (np. 200–500ms). Konfiguruj timeoutIntervalForRequest na 15s, aby unikać zawieszeń.

Czy proxy HTTP w URLSession narusza App Transport Security?

Nie. Proxy HTTP działa jako tunel dla ruchu HTTPS — sesja TLS jest nawiązywana między aplikacją a serwerem docelowym, a proxy tylko przekazuje zaszyfrowane pakiety. ATS wymaga TLS 1.2+ dla połączenia końcowego, a nie dla proxy. Nie musisz wyłączać ATS, chyba że łączysz się z celem HTTP (nie HTTPS).

Sprawdź konfigurację proxy w kilka sekund

Darmowy tester proxy — potwierdź, że Twoje IP są szybkie, anonimowe i nieblokowane.

Sprawdź proxy za darmo
← Powrót do Bloga