5

I Hava aplikację w Google Play, otrzymałem mail od Google mówi, że:niebezpiecznym realizacja X509TrustManager interfejsu Google

Twoja aplikacja (e) na końcu tej wiadomości użyć niebezpieczne implementacja interfejsu X509TrustManager. W szczególności implementacja ignoruje wszystkie błędy sprawdzania certyfikatów SSL podczas nawiązywania połączenia HTTPS ze zdalnym hostem, przez co twoja aplikacja jest podatna na ataki typu "man-in-the-middle".

Aby poprawnie obsłużyć sprawdzanie certyfikatu SSL, zmień kod w metodzie checkServerTrusted w niestandardowym interfejsie X509TrustManager, aby zwiększyć wyjątek CertificateException lub IllegalArgumentException, gdy certyfikat prezentowany przez serwer nie spełnia Twoich oczekiwań.

Moja aplikacja używa "https", mój checkServerTrusted() jest następujący:

TrustManager tm = new X509TrustManager() { 
     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     } 

     public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 

     } 

     public X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 
    }; 

Potem zmodyfikować tę funkcję:

TrustManager tm = new X509TrustManager() { 
     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     } 

     public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
      if (chain == null) { 
       throw new IllegalArgumentException("checkServerTrusted: X509Certificate array is null"); 
      } 

      if (!(chain.length > 0)) { 
       throw new IllegalArgumentException("checkServerTrusted: X509Certificate is empty"); 
      } 

      if (!(null != authType && authType.equalsIgnoreCase("RSA"))) { 

       throw new CertificateException("checkServerTrusted: AuthType is not RSA"); 
      } 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 

zwyczaj SSLSocketFactory:

public class MySSLSocketFactory extends SSLSocketFactory { 
SSLContext sslContext = SSLContext.getInstance("TLS"); 

public MySSLSocketFactory(KeyStore ctx) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { 
    super(ctx); 

    TrustManager tm = new X509TrustManager() { 
     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     } 

     public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 
    }; 

    sslContext.init(null, new TrustManager[]{tm}, null); 
} 

@Override 
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { 
    return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); 
} 

@Override 
public Socket createSocket() throws IOException { 
    return sslContext.getSocketFactory().createSocket(); 
} 

}

funkcja HttpClient:

private static HttpClient getHttpClient(int timeout) { 
    if (null == mHttpClient) { 

     try { 
      KeyStore trustStore = KeyStore.getInstance(KeyStore 
        .getDefaultType()); 
      trustStore.load(null, null); 
      SSLSocketFactory sf = new MySSLSocketFactory(trustStore); 
      sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

      HttpParams params = new BasicHttpParams(); 

      HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
      HttpProtocolParams.setContentCharset(params, 
        HTTP.DEFAULT_CONTENT_CHARSET); 
      HttpProtocolParams.setUseExpectContinue(params, true); 


      ConnManagerParams.setTimeout(params, timeout); 

      HttpConnectionParams.setConnectionTimeout(params, timeout); 

      HttpConnectionParams.setSoTimeout(params, timeout); 


      SchemeRegistry schReg = new SchemeRegistry(); 
      schReg.register(new Scheme("http", PlainSocketFactory 
        .getSocketFactory(), 80)); 
      schReg.register(new Scheme("https", sf, 443)); 

      ClientConnectionManager conManager = new ThreadSafeClientConnManager(
        params, schReg); 

      mHttpClient = new DefaultHttpClient(conManager, params); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return new DefaultHttpClient(); 
     } 
    } 
    return mHttpClient; 
} 

Ale nie wiem dobrze o tym, po prostu zmodyfikować mój kod, co powiedział, że e-mail, myślę, że nie sloved ten problem.What jest to ostrzeżenie wszystkim chodzi? Jak to rozwiązać?

+2

Dlaczego masz ten 'TrustManager' w pierwszej p koronka? Nie musisz używać SSL. – CommonsWare

+0

Czy używasz pakietu SDK innej firmy? – Idan

+0

@CommonsCo mam robić? – zys

Odpowiedz

5

Znalazłem this solution, działa dobrze!

X509TrustManager:

public class EasyX509TrustManager 
    implements X509TrustManager { 

private X509TrustManager standardTrustManager = null; 

/** 
* Constructor for EasyX509TrustManager. 
*/ 
public EasyX509TrustManager(KeyStore keystore) 
     throws NoSuchAlgorithmException, KeyStoreException { 
    super(); 
    TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    factory.init(keystore); 
    TrustManager[] trustmanagers = factory.getTrustManagers(); 
    if (trustmanagers.length == 0) { 
     throw new NoSuchAlgorithmException("no trust manager found"); 
    } 
    this.standardTrustManager = (X509TrustManager) trustmanagers[0]; 
} 

/** 
* @see X509TrustManager#checkClientTrusted(X509Certificate[], String authType) 
*/ 
public void checkClientTrusted(X509Certificate[] certificates, String authType) 
     throws CertificateException { 
    standardTrustManager.checkClientTrusted(certificates, authType); 
} 

/** 
* @see X509TrustManager#checkServerTrusted(X509Certificate[], String authType) 
*/ 
public void checkServerTrusted(X509Certificate[] certificates, String authType) 
     throws CertificateException { 
    if ((certificates != null) && (certificates.length == 1)) { 
     certificates[0].checkValidity(); 
    } else { 
     standardTrustManager.checkServerTrusted(certificates, authType); 
    } 
} 

/** 
* @see X509TrustManager#getAcceptedIssuers() 
*/ 
public X509Certificate[] getAcceptedIssuers() { 
    return this.standardTrustManager.getAcceptedIssuers(); 
} 

} 

SSLSocketFactory:

public class EasySSLSocketFactory implements LayeredSocketFactory { 

private SSLContext sslcontext = null; 

private static SSLContext createEasySSLContext() throws IOException { 
    try { 
     SSLContext context = SSLContext.getInstance("TLS"); 
     context.init(null, new TrustManager[]{new EasyX509TrustManager(
       null)}, null); 
     return context; 
    } catch (Exception e) { 
     throw new IOException(e.getMessage()); 
    } 
} 

private SSLContext getSSLContext() throws IOException { 
    if (this.sslcontext == null) { 
     this.sslcontext = createEasySSLContext(); 
    } 
    return this.sslcontext; 
} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#connectSocket(Socket, 
* String, int, InetAddress, int, 
* HttpParams) 
*/ 
public Socket connectSocket(Socket sock, String host, int port, 
          InetAddress localAddress, int localPort, HttpParams params) 
     throws IOException, UnknownHostException, ConnectTimeoutException { 
    int connTimeout = HttpConnectionParams.getConnectionTimeout(params); 
    int soTimeout = HttpConnectionParams.getSoTimeout(params); 

    InetSocketAddress remoteAddress = new InetSocketAddress(host, port); 
    SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); 

    if ((localAddress != null) || (localPort > 0)) { 
     // we need to bind explicitly 
     if (localPort < 0) { 
      localPort = 0; // indicates "any" 
     } 
     InetSocketAddress isa = new InetSocketAddress(localAddress, 
       localPort); 
     sslsock.bind(isa); 
    } 

    sslsock.connect(remoteAddress, connTimeout); 
    sslsock.setSoTimeout(soTimeout); 
    return sslsock; 

} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#createSocket() 
*/ 
public Socket createSocket() throws IOException { 
    return getSSLContext().getSocketFactory().createSocket(); 
} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#isSecure(Socket) 
*/ 
public boolean isSecure(Socket socket) throws IllegalArgumentException { 
    return true; 
} 

/** 
* @see LayeredSocketFactory#createSocket(Socket, 
* String, int, boolean) 
*/ 
public Socket createSocket(Socket socket, String host, int port, 
          boolean autoClose) throws IOException, UnknownHostException { 
    return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); 
} 

// ------------------------------------------------------------------- 
// javadoc in org.apache.http.conn.scheme.SocketFactory says : 
// Both Object.equals() and Object.hashCode() must be overridden 
// for the correct operation of some connection managers 
// ------------------------------------------------------------------- 

public boolean equals(Object obj) { 
    return ((obj != null) && obj.getClass().equals(
      EasySSLSocketFactory.class)); 
} 

public int hashCode() { 
    return EasySSLSocketFactory.class.hashCode(); 
} 

} 

Następnie:

SchemeRegistry schReg = new SchemeRegistry(); 
      schReg.register(new Scheme("http", PlainSocketFactory 
        .getSocketFactory(), 80)); 
      schReg.register(new Scheme("https", new EasySSLSocketFactory(), 443)); 
+0

Nie używaj tego bardzo złego kodu! Kod umożliwia ataki typu "człowiek w środku" i renderuje cały punkt protokołu SSL o wartości zerowej. Metoda 'checkValidity()' sprawdza tylko, czy certyfikat nie wygasł i nic więcej, co oznacza, że ​​ten kod z przyjemnością zaakceptuje ŻADNY nie wygasły certyfikat, nawet jeśli certyfikat jest fałszywy, dla innego serwera i nie został podpisany przez nic. – Nohus

+0

@Nohus Wiem, ale moim celem jest zaakceptowanie całego certyfikatu – zys

+0

Wszystko w porządku, jeśli jest to naprawdę potrzebne, ale nie odpowiada na pytanie, jak rozwiązać problem bezpieczeństwa zauważony przez Google. – Nohus

1

Proponowane przez Ciebie modyfikacje nie usuwają luki w zabezpieczeniach. Twój kod będzie nadal akceptował każdy poprawnie sformatowany certyfikat, niezależnie od jego ważności.

Jeśli nie masz pewności, jak poprawnie zweryfikować certyfikaty, po prostu usuń niestandardowego menedżera zaufania. Nie potrzebujesz tego, chyba że robisz coś niezwykłego.

+0

Moja aplikacja jest monitorem serwera, użytkownicy mogą dodać dowolną witrynę lub serwer do pingowania. Jeśli usunę niestandardowy menedżer zaufania, będę musiał również usunąć niestandardowy obiekt SSLSocketFactory. – zys

+0

Być może możesz dodać interfejs, aby użytkownicy mogli dodawać samopodpisane certyfikaty, które chcą umieścić na białej liście? To i tak powinno być rzadkim zjawiskiem. – Antimony

+0

Po usunięciu niestandardowego TrsustManager, podczas odwiedzania witryny internetowej certyfikat jest dostosowywany przez samą stronę internetową. Pojawi się ostrzeżenie, że certyfikat nie jest bezpieczny. – zys