android - related - how to use hashtags on instagram
FijaciĆ³n segura: javax.net.ssl.SSLPeerUnverifiedException: sin certificado de par (4)
Hay docenas de publicaciones sobre este tema (javax.net.ssl.SSLPeerUnverifiedException: sin certificado de pares) pero no he encontrado nada que me funcione.
Muchas publicaciones (como this , y this ) "resuelven" esto al permitir que se acepten todos los certificados, pero, por supuesto, esta no es una buena solución para otra cosa que no sean las pruebas.
Otros parecen bastante localizados y no funcionan para mí. Realmente espero que alguien tenga una idea que me falte.
Entonces, mi problema: estoy probando en un servidor accesible solo a través de la red local, conectándose a través de HTTPS. Hacer la llamada que necesito a través del navegador funciona bien. No se queja de los certificados y si revisa los certificados, todo se ve bien.
Cuando pruebo en mi dispositivo Android, obtengo javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Aquí está el código que lo llama:
StringBuilder builder = new StringBuilder();
builder.append( /* stuff goes here*/ );
httpGet.setEntity(new UrlEncodedFormEntity(nameValuePairs));
ResponseHandler<String> responseHandler = new BasicResponseHandler();
// Execute HTTP Post Request. Response body returned as a string
HttpClient httpClient = MyActivity.getHttpClient();
HttpGet httpGet = new HttpGet(builder.toString());
String jsonResponse = httpClient.execute(httpGet, responseHandler); //Line causing the Exception
Mi código para MyActivity.getHttpClient()
:
protected synchronized static HttpClient getHttpClient(){
if (httpClient != null)
return httpClient;
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_CONNECTION);
HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);
HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1);
//Thread safe in case various AsyncTasks try to access it concurrently
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager cm = new ThreadSafeClientConnManager(httpParameters, schemeRegistry);
httpClient = new DefaultHttpClient(cm, httpParameters);
CookieStore cookieStore = httpClient.getCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
return httpClient;
}
Cualquier ayuda sería muy apreciada.
Editar
También por mencionar que tuve otros problemas de SSL con otra aplicación, pero al agregar la porción de SchemeRegistry
se me arregló antes.
Editar 2
Hasta ahora solo he probado en Android 3.1, pero necesito que esto funcione en Android 2.2+ independientemente. Acabo de probar en el navegador en la pestaña de Android (Android 3.1) y se queja del certificado. Está bien en mi navegador de PC, pero no en el navegador de Android o en mi aplicación.
Editar 3
Resulta que el navegador iOS también se queja de eso. Estoy empezando a pensar que es un problema de la cadena de certificados que se describe aquí (el certificado SSL no es de confianza, solo en el móvil )
En mi caso, todo solía funcionar bien. De repente, después de 2 días, mi dispositivo no mostró ningún sitio https o enlace de imagen.
Después de algunas investigaciones, resultó que Mi configuración de tiempo no estaba actualizada en el dispositivo.
Cambié mi configuración de tiempo correctamente y funcionó.
Pruebe el siguiente código: -
BasicHttpResponse httpResponse = null;
HttpPost httppost = new HttpPost(URL);
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is
// established.
int timeoutConnection = ConstantLib.CONNECTION_TIMEOUT;
HttpConnectionParams.setConnectionTimeout(httpParameters,
timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = ConstantLib.CONNECTION_TIMEOUT;
HttpConnectionParams
.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(
httpParameters);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair(ConstantLib.locale,
locale));
Resultó que mi código estaba bien y el problema era que el servidor no devolvía la cadena de certificados completa. Para obtener más información, consulte esta publicación de SO y esta publicación de superusuario:
El certificado SSL no es de confianza, solo en dispositivos móviles
https://superuser.com/questions/347588/how-do-ssl-chains-work
Tuve esta excepción cuando utilicé el certificado autofirmado + dirección IP. Solo agregue estas líneas
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
y su HttpURLConnection funcionará. ¡Ese truco no está relacionado con la validación contra CA! Entonces, si especifico una CA incorrecta y uso ese truco, obtendré otra excepción. Entonces el host sigue siendo de confianza
Por las dudas, dejaré el código para especificar su propia CA aquí:
String certStr = context.getString(R.string.caApi);
X509Certificate ca = SecurityHelper.readCert(certStr);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
ks.setCertificateEntry("caCert", ca);
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
No te olvides de usar la función cool buildTypes y coloca diferentes CA para depurar / liberar en la carpeta res.