java 안드로이드 - HTTP 프록시를 통해 SSL 소켓을 연결하는 방법은 무엇입니까?




우회 https (4)

javax.net lib 를 사용해야합니다. javax.net.ssl. *을 사용하여 대상에 아카이브 할 수 있습니다.

오라클 워드 프로세서를 사용하여 솔루션을 얻을 수 있다고 생각합니다. 여기에 대한 링크가 있습니다.

SSLSocketClientWithTunneling

SSL 소켓이있는 서버에 Java (Android)를 사용하여 연결하려고합니다. 이것은 HTTP 데이터가 아닙니다. 이것은 텍스트와 바이너리 데이터가 혼합 된 독점적 인 프로토콜입니다.

나는 HTTP 프록시를 통해 SSL 연결을 중계하고 싶지만, 나는 그것에 많은 문제가있다. 지금 내가 사용하는 시나리오와 브라우저가 오징어 프록시와 함께 사용하는 것처럼 보이는 시나리오는 다음과 같습니다.

[클라이언트] -> [http 연결] -> [프록시] -> [SSL 연결] -> [서버]

이것은 프록시가 SSL 연결을 한 후에 TLS 협상이 즉시 수행되기 때문에 브라우저에서 작동합니다. 그러나 내 코드는 그렇게하지 않는 것 같습니다.

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);

문제는 createSocket이 결코 돌아 오지 않는다는 것입니다. 프록시 시스템에서 wireshark 덤프를 사용하면 TCP 핸드 셰이크가 프록시와 서버간에 발생한다는 것을 알 수 있습니다. 웹 세션의 덤프를 사용하면 클라이언트가 대개이 시점에서 SSL 핸드 셰이크를 시작한다는 것을 알 수 있습니다. 이는 내 시나리오에서는 발생하지 않습니다.

이것은 인증서가 결코 나에게 돌아 오지 않으며 결코 검증되지 않기 때문에 트러스트 매니저에 문제가되지 않습니다.

편집하다 :

토론 후에,이 코드는 내가 실행하려고하는 코드의보다 완전한 버전입니다. 매개 변수로 간단한 (새로운 소켓 (...)) 위의이 버전은 내가 나중에 시도한 것입니다.

디버깅하려는 코드의 원본 버전이 throw됩니다.
java.net.ConnectException: failed to connect to /192.168.1.100 (port 443): connect failed: ETIMEDOUT (Connection timed out)

순서는 다음과 같습니다 (약간 다시 단순화 됨).

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]

그런 다음 다음 코드를 사용하여 응답을 읽으십시오.

    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 )
    {
    }

이 코드는 SSL 없이도 작동하기 때문에 작동한다고 말할 수 있습니다. 여기에서 생성 된 소켓 인 proxySocket 은 원래 예제 에서처럼 새로 작성하는 대신 createSocket 함수에 전달되는 소켓입니다.


java.net.Proxy 또는 https.proxyHost/proxyPort 속성은 Socket. 아닌 HttpURLConnection, 통한 HTTP 프록시 만 지원합니다 Socket.

그 자신의 SSLSocket 에 대해 작업하려면, 일반 텍스트 소켓을 작성하고 HTTP CONNECT 명령을 실행 한 다음 200 응답을 확인한 다음 SSLSocket. 랩핑하면됩니다 SSLSocket.

편집 CONNECT 명령을 보낼 때 물론 소켓을 닫아서는 안됩니다. 답장을 읽을 때 BufferedReader, 사용하면 안됩니다 BufferedReader, 그렇지 않으면 데이터가 손실됩니다. 그 행을 수동으로 읽거나 사용되지 않는 DataInputStream.readLine(), 사용하십시오. 또한 RFC 2616을 완전히 따라야합니다.


지금은 타겟 솔루션을 테스트 / 작성할 시간이 없지만 STARTTLS : recv를 사용하여 소켓을 SSLSocket으로 업 그레 이드하는 것은 기본 문제를 해결하는 것으로 보입니다.

귀하의 경우에는 프록시에 연결하고 프록시 연결을 실행 한 다음 연결을 업그레이드해야합니다. 본질적으로 CONNECT는 참조 된 질문에서 STARTTLS 대신 사용되며 "670"에 대한 확인은 필요하지 않습니다.


아래의 앱 아이콘에 알림 개수 추가 단계 정의

단계 :

  1. mavenCentral을 빌드 스크립트에 추가하십시오.

    저장소 {mavenCentral ()}

  2. 앱 gradle에 종속성을 추가하십시오.

    의존성 {compile 'me.leolin : ShortcutBadger : [email protected]'또는 컴파일 'me.leolin : ShortcutBadger : [email protected]'}

  3. 앱 아이콘에 표시 알림 개수를 위해 아래 코드를 추가하십시오.

    int badgeCount = 1; ShortcutBadger.applyCount (context, badgeCount); // for 1.1.4 또는 ShortcutBadger.with (getApplicationContext ()). count (badgeCount); // for 1.1.3

  4. 배지를 제거하려면

    ShortcutBadger.removeCount (context); // 1.1.4 ShortcutBadger.with (getApplicationContext ()). remove (); // 1.1.3 또는 ShortcutBadger.applyCount (context, 0); // for 1.1.4 ShortcutBadger.with (getApplicationContext ()). count (0); // for 1.1.3





java android ssl