2013-05-03 12 views
6

Piszę prosty program proxy HTTPS z Javą do celów edukacyjnych. Mój program nasłuchuje na porcie (na przykład) dla przychodzących żądań HTTPS z przeglądarki (np. Firefox), analizuje żądanie i przekazuje je do wybranego miejsca docelowego (na przykład https://www.comodo.com).Wdrażanie prostej aplikacji Proxy HTTPS w Javie?

Ustawienia proxy Firefoksa służą do korzystania z mojego portu do połączeń SSL (127.0.0.1 : 7443).

Mój kod jest krótka i prosta:

static // initializer 
{ 
    System.setProperty("javax.net.ssl.keyStore", "MyKeyStore"); 
    System.setProperty("javax.net.ssl.keyStorePassword", "password"); 
} 

SSLServerSocketFactory ssFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 

try { 
    SSLServerSocket listener = (SSLServerSocket) ssFactory.createServerSocket(port, 64); 
    listener.setUseClientMode(false); 
    listener.setWantClientAuth(false); 
    listener.setNeedClientAuth(false); 

    SSLSocket connection = (SSLSocket) listener.accept(); 
    browser.startHandshake(); /* <<== Exception throws at this line */ 

} catch (IOException ex) { 
    ex.printStackTrace(System.err); 
} 

Ale Łapię następujący wyjątek:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 

Wyjątkiem mówi, że połączenie może być zwykły tekst, ale tylko połączeń HTTPS z Firefoxa są ustawione na używanie tego portu. Mam zalogowany co Firefox wysyła do mojej aplikacji, która jest taka:

CONNECT www.comodo.com:443 HTTP/1.1 
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0 
Proxy-Connection: keep-alive 
Connection: keep-alive 
Host: www.comodo.com 

Firefox mówi Palin-tekst i myślę CONNECT jest polecenie SOCKS (nie jestem pewien, choć), gdzie nie mam ustaw dowolne ustawienia SOCKS w Firefoksie. Poniżej znajduje się zrzut ekranu z ustawień proxy Firefoksa:

Firefox Proxy Settings

Co ja tu brakuje? Co muszę zrobić, aby działało to z przeglądarką Firefox lub inną przeglądarką?!

---------------------------------------------- --------------------------------

Dla tych, którzy myślą, że jest to duplikat another question i że ma na drugie pytanie mam do powiedzenia: tak, oba pytania mają korzenie w podobnym problemie, ale jedyna odpowiedź w cytowanym pytaniu dotyczy użycia gniazd SSL, które okazały się mylące i zaowocowały nowym pytaniem. Tak więc chociaż są one nakierowane na podobny problem, to pytanie pokazuje zupełnie inną, a jednak wprowadzającą w błąd ścieżkę do rozwiązania problemu, a zatem może dostarczyć użytecznych wskazówek dla przyszłych osób borykających się z takim problemem.

+1

To nie jest duplikat cytowanego pytania. Te dwa pytania są wyraźnie różne i nie ma akceptowalnego rozwiązania w przywołanym pytaniu. –

+0

Dla tych, którzy znaleźli się w tym wątku: możesz być zainteresowany przykładem pracy _TheConstructor_ tutaj: http://stackoverflow.com/questions/16351413/java-https-proxy-using-https-proxyport-and-https- proxyhost – Trinimon

Odpowiedz

6

Pozbądź się wszystkich SSL. Przetwórz przychodzące polecenie CONNECT, utwórz połączenie tekstowe z serwerem nadrzędnym, a następnie rozpocznij kopiowanie bajtów. Przeglądarka i serwer będą komunikować się z protokołem SSL, ale nie musisz w ogóle.

+0

Nie sądzę, że to jest poprawne ... Próbowałem wcześniej tego rozwiązania i nie działało ... Możesz sprawdzić moje poprzednie pytanie dotyczące tego rozwiązania na http://stackoverflow.com/questions/14153662/java-https-connection-forwarding –

+1

Z pewnością jest poprawny. Zobacz dokument RFC. Oczywiście, przeglądarka wysyła polecenie CONNECT w postaci zwykłego tekstu i oczywiście możesz wywnioskować, że oczekuje odpowiedzi w postaci zwykłego tekstu, i oczywiście, jeśli przeniesiesz wszystkie inne bajty w obu kierunkach, bez konieczności dalszej interwencji, wszelkie problemy pozostające koniec serwera lub przeglądarki. Musisz być bardziej konkretny niż "to nie zadziałało". Inne zadane przez ciebie pytanie również nie dostarcza żadnych dalszych informacji. – EJP

+0

Jak już powiedziałem, próbowałem dokładnie tego, co sugerujesz, a właściwie to była pierwsza metoda, która przyszła mi do głowy, ale się nie udało. Jak wspomniano w innym zadanym przeze mnie pytaniu, przesyłanie zapytania przeglądarki do serwera "CONNECT" zawsze skutkuje błędem 'connection reset', co oznacza, że ​​serwer nie odpowiada i zamyka połączenie ... Takie zachowanie jest oczywiste, ponieważ serwer nasłuchuje komunikatu "HELLO" SSL/TLS na 443 i otrzymuje komunikat 'CONNECT', który nie jest oczekiwanym komunikatem SSL/TLS. –

3

Twoja konfiguracja korzysta z tunelowania HTTP, gdzie początkowe żądanie wysłane do serwera proxy to , a nie szyfrowanie SSL; ponieważ gniazdo z obsługą SSL oczekuje uzgadniania SSL, zgłasza wyjątek.

W tym mechanizmie, klient prosi serwer proxy HTTP do przekazania połączenia TCP do żądanego miejsca docelowego za pomocą „connect” HTTP metody. Następnie serwer przystępuje do wykonania połączenia w imieniu klienta . Po ustanowieniu połączenia przez serwer, serwer proxy kontynuuje przesyłanie proxy strumienia TCP do iz klienta . Zauważ, że tylko początkowe żądanie połączenia to HTTP - po , że serwer po prostu pośredniczy w ustanowieniu połączenia TCP.

Możesz przeczytać więcej na ten temat na stronie wiki HTTP Tunneling. Aby zobaczyć to w akcji, można rozpocząć serwer netcat i ustawić proxy Firefoksa zwrócić do tego portu:

nc -l 8000 

Teraz w rodzaju Firefox w https://www.google.com i zbadać wyjście NC:

CONNECT www.google.com:443 HTTP/1.1 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) 
Proxy-Connection: keep-alive 
Connection: keep-alive 
Host: www.google.com 

I to jest całkowicie w zwykłym tekście. Poniższy diagram pokazuje, jak proxy powinien się komunikować.

enter image description here

Powiązane problemy