2015-01-16 31 views
12

SSL soketli bir sunucuya bağlanmak için Java (Android) kullanmaya çalışıyorum. Lütfen bunun HTTP verisi olmadığını unutmayın. Bu, metin ve ikili veri karışımıyla özel protokoldür.SSL proxy'si bir HTTP proxy üzerinden nasıl bağlanır?

Bu SSL bağlantısını bir HTTP proxy üzerinden aktarmak istiyorum ancak bununla ilgili birçok sorunla karşılaşıyorum. Şu anda kullandığım ve tarayıcımın bir kalamar proxy'si ile kullanıldığı göründüğü senaryo şu

[istemci] -> [http bağlantı] -> [proxy] -> [ssl bağlantı] -> [sunucu]

Bu, tarayıcı için çalışır, çünkü vekil ssl bağlantısını yaptıktan sonra, hemen bir TLS anlaşması gerçekleşir. Ancak kodum bunu yapmıyor gibi görünüyor. Ben

final TrustManager[] trustManager = new TrustManager[] { new MyX509TrustManager() }; 
final SSLContext context = SSLContext.getInstance("TLS"); 
context.init(null, trustManager, null); 
SSLSocketFactory factory = context.getSocketFactory(); 
Socket s = factory.createSocket(new Socket(proxy_ip, 3128), hostName, port, true); 

sorun createSocket ASLA GERİ DÖNÜYOR olmasıdır. Proxy makineden bir wireshark dökümü ile, vekil sunucu ile sunucu arasında bir tcp el sıkışma olduğunu görebiliyorum. Web oturumlarındaki dökümlerle, müşterimin genellikle senaryoda gerçekleşmeyen bir SSL el sıkışma başlattığını görebiliyorum.

Bu sertifika yöneticisi ile ilgili bir sorun değildir çünkü sertifika asla bana geri dönmez ve hiçbir zaman doğrulanmaz.

DÜZENLEME:

tartışmalar sonrasında

, bu şimdiye yönetmeye çalışıyorum kod daha tam sürümüdür. Yukarıdaki bu sürüm ile basit (yeni Soket (...)) parametresi daha sonra denediğim bir şeydir.

final Socket proxySocket = new Socket(); 
proxySocket.connect(proxyAddress, 2000); // 2 seconds as the connection timeout for connecting to the proxy server 
[Start a thread and write to outputStream=socket.getOutputStream()] 
final String proxyRequest = String.format("CONNECT %s:%d HTTP/1.1\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nHost: %s:%d\r\n\r\n", hostName, port, hostName, port); 
outputStream.close(); // Closing or not doesn't change anything 
[Stop using that thread and let it exit by reaching the end of its main function] 

Ardından aşağıdaki yanıtı okuyun:

Ben Hata ayıklamak çalışıyorum kod orijinal versiyonu dizisi (biraz tekrar basitleştirilmiş) şu şekilde olmaktadır
java.net.ConnectException: failed to connect to /192.168.1.100 (port 443): connect failed: ETIMEDOUT (Connection timed out)

atar kodu:

final InputStreamReader isr = new InputStreamReader(proxySocket.getInputStream()); 
    final BufferedReader br = new BufferedReader(isr); 
    final String statusLine = br.readLine(); 

    boolean proxyConnectSuccess = false; 
    // readLine consumed the CRLF 
    final Pattern statusLinePattern = Pattern.compile("^HTTP/\\d+\\.\\d+ (\\d\\d\\d) .*"); 
    final Matcher statusLineMatcher = statusLinePattern.matcher(statusLine); 
    if (statusLineMatcher.matches()) 
    { 
     final String statusCode = statusLineMatcher.group(1); 
     if (null != statusCode && 0 < statusCode.length() && '2' == statusCode.charAt(0)) 
     { 
      proxyConnectSuccess = true; 
     } 
    } 

    // Consume rest of proxy response 
    String line; 
    while ("".equals((line = br.readLine())) == false) 
    { 
    } 

Bu kodun SSL olmadan çalıştığından çalıştığını söyleyebilirim. Burada oluşturulan soket, proxySocket, orijinal örneğimde olduğu gibi anında yeni bir tane oluşturmak yerine, createSocket işlevine iletilendir.

+0

java.net.Proxy HTTP altında çalışmaz. SOCKS proxy gerektiriyor gibi görünüyor. Güneş os için bir yama buldum ama android için bir şey yok. Bu, Android'in üçüncü taraf uygulamaları olmadan HTTPS/SOCKS desteği sağlayamadığı için HTTP için çalışmasının çok önemlidir (varsayılan yükleme, Ocak 2015'te yeterli yapılandırma sağlamaz). – Eric

+0

Bir HTTP proxy'si üzerinden bir SSL soketine bağlanıyorsanız, mümkün olan durumlarda websockets'ları düşünmenizi öneririz - özellikle "java.net.ConnectException: hata iletisi" /192.168.1.100 (bağlantı noktası 443) 'e bağlanamadığı için " standart HTTPS bağlantı noktasına bağlanmak için bir girişimi gösterir. Tabii ki, kullanım durumunuza bağlıdır .... –

cevap

13

java.net.Proxy veya https.proxyHost/proxyPort özellikleri, yalnızca kendi bir SSLSocket için bu işi yapmak için bir Socket.

aracılığıyla HttpURLConnection, değil aracılığıyla HTTP vekili desteklemek, bütün düz metin soket oluşturmaktır için, meselenin bir HTTP CONNECT gerekir üzerinde komut, CONNECT komutunu gönderirken, elbette, soket gelmemeliyiz 200 yanıtını kontrol edin ve ardından bir SSLSocket.

EDIT'e sarın; ve cevabını okurken bir BufferedReader, kullanmamalısınız, aksi takdirde veri kaybedersiniz; çizgiyi el ile okuyun veya kullanımdan kaldırılmasına rağmen DataInputStream.readLine(), kullanın. Ayrıca RFC 2616'yı tamamen takip etmeniz gerekiyor.

1

Şimdi hedeflenmiş bir çözümü sınamak/yazmak için zamanım yok, ancak Upgrading socket to SSLSocket with STARTTLS: recv failed temel sorunu karşılar gibi görünüyor.

Sizin durumunuzda, proxy'ye bağlanmanız, bir proxy bağlantısı kurmanız, ardından bağlantıyı yükseltmeniz gerekir - bağlantıyı güncellemeniz gerekir - esas olarak, CONNECT, başvurulan sorudaki STARTTLS yerini alır ve "670" kontrolü gerekli değildir .

+1

Ama bunun yerine HTTP '200' için bir kontrol gereklidir. – EJP

6

javax.net lib kullanmanız gerekir. javax.net.ssl ​​kullanarak hedefinize arşivleyebilirsiniz. *.

Sanırım oracle belgelerini kullanarak çözüm alabilirsiniz. İşte bunun için bağlantı.

SSLSocketClientWithTunneling

+2

Bu bağlantıda küçük bir hata var. İstek satırlarından biri \ n ile sonlandırıldı, '\ r \ n olmalıdır. – EJP

İlgili konular