¿Cómo hacer un HTTPS POST de Android?
Quiero hacer un HTTPS post método para enviar algunos datos de mi aplicación Android a mi sitio web.
HttpURLConnection
primero HttpURLConnection
y funciona bien con mi URL HTTP. Mi sitio web de producción está en HTTPS y quiero enviar el mismo POST usando HttpsURLConnection
. ¿Puede alguien ayudarme a usar la clase correctamente?
- HttpClient falla con Handshake Falló en Android 5.0 Lollipop
- Certificado ssl de android
- Cliente SSL en Android
- Alerta de seguridad de Google Play para TrustManager inseguro
- ¿Hay algún almacenamiento de certificados de sistema en Android?
Encontré alguna fuente en este enlace :
KeyStore keyStore = ...; TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(keyStore); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); URL url = new URL("https://www.example.com/"); HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); urlConnection.setSSLSocketFactory(context.getSocketFactory()); InputStream in = urlConnection.getInputStream();
¿Cuál debe ser el valor de KeyStore keyStore = ...;
?
Intenté enviar los datos usando la misma HttpURLConnection
, pero estoy viendo algunos datos del POST se pierde o en el error.
He intentado el método de esta pregunta . Estoy pegando mi código abajo
String urlParameters="dateTime=" + URLEncoder.encode(dateTime,"UTF-8")+ "&mobileNum="+URLEncoder.encode(mobileNum,"UTF-8"); URL url = new URL(myurl); HttpsURLConnection conn; conn=(HttpsURLConnection)url.openConnection(); // Create the SSL connection SSLContext sc; sc = SSLContext.getInstance("TLS"); sc.init(null, null, new java.security.SecureRandom()); conn.setSSLSocketFactory(sc.getSocketFactory()); conn.setConnectTimeout(HTTP_CONNECT_TIME_OUT); conn.setReadTimeout(HTTP_READ_TIME_OUT); //set the output to true, indicating you are outputting(uploading) POST data conn.setDoOutput(true); //once you set the output to true, you don't really need to set the request method to post, but I'm doing it anyway conn.setRequestMethod("POST"); conn.setFixedLengthStreamingMode(urlParameters.getBytes().length); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); PrintWriter out = new PrintWriter(conn.getOutputStream()); out.print(urlParameters); out.close(); InputStream is = conn.getInputStream(); BufferedReader in = new BufferedReader(new InputStreamReader(is)); String inputLine; while ((inputLine = in.readLine()) != null) { response += inputLine; }
El error que estoy recibiendo está abajo:
05-12 19:36:10.758: W/System.err(1123): java.io.FileNotFoundException: https://www.myurl.com/fms/test 05-12 19:36:10.758: W/System.err(1123): at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177) 05-12 19:36:10.758: W/System.err(1123): at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:270) 05-12 19:36:10.758: W/System.err(1123): at .httpRequest(SMSToDBService.java:490) 05-12 19:36:10.758: W/System.err(1123): at com..access$0(SMSToDBService.java:424) 05-12 19:36:10.758: W/System.err(1123): at com.$ChildThread$1.handleMessage(SMSToDBService.java:182) 05-12 19:36:10.758: W/System.err(1123): at android.os.Handler.dispatchMessage(Handler.java:99) 05-12 19:36:10.758: W/System.err(1123): at android.os.Looper.loop(Looper.java:156) 05-12 19:36:10.758: W/System.err(1123): at com.$ChildThread.run(SMSToDBService.java:303)
- Generación e instalación de certificados SSL
- Excepción terminada handshake de https de Android
- Reutilizando sesiones SSL en Android con HttpClient
- Error SSL de Android: certificado no de confianza ... a veces
- SSLSocket se bloquea en getInputStream cuando el dispositivo android está en wifi
- Android ssl: javax.net.ssl.SSLPeerUnverifiedException: Ningún certificado de igual (una vez más)
- Error de E / S durante la llamada al sistema, Conexión restablecida por pares
- DownloadManager: entiende la política de reintentos y los códigos de error
Puede usar las CA predeterminadas que se definen en el dispositivo android, que está bien para cualquier web pública.
Si tiene un certificado autofirmado, puede aceptar todos los certificados (riesgosos, abiertos a ataques de intermediario) o crear su propio TrustManagerFactory
, algo fuera de este ámbito.
He aquí un código para usar las CAs predeterminadas para una llamada de POST de https:
private InputStream getInputStream(String urlStr, String user, String password) throws IOException { URL url = new URL(urlStr); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); // Create the SSL connection SSLContext sc; sc = SSLContext.getInstance("TLS"); sc.init(null, null, new java.security.SecureRandom()); conn.setSSLSocketFactory(sc.getSocketFactory()); // Use this if you need SSL authentication String userpass = user + ":" + password; String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT); conn.setRequestProperty("Authorization", basicAuth); // set Timeout and method conn.setReadTimeout(7000); conn.setConnectTimeout(7000); conn.setRequestMethod("POST"); conn.setDoInput(true); // Add any data you wish to post here conn.connect(); return conn.getInputStream(); }
Para leer la respuesta:
String result = new String(); InputStream is = getInputStream(urlStr, user, password); BufferedReader in = new BufferedReader(new InputStreamReader(is)); String inputLine; while ((inputLine = in.readLine()) != null) { result += inputLine; }
Usted puede echar un vistazo a esta pregunta que le pregunté hace unos días:
Cambiar la solicitud de publicación HTTP a HTTPS:
He proporcionado allí una solución que trabajó para mí, que básicamente acepta cualquier certificado autofirmado. Como se ha dicho aquí esta solución no es recomendable, ya que no es seguro y abierto a un hombre en el medio ataques.
Aquí está el código:
EasySSLSocketFactory:
public class EasySSLSocketFactory implements SocketFactory, 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(java.net.Socket, java.lang.String, int, * java.net.InetAddress, int, org.apache.http.params.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(java.net.Socket) */ public boolean isSecure(Socket socket) throws IllegalArgumentException { return true; } /** * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.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(); } }
EasyX509TrustManager:
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 javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) */ public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException { standardTrustManager.checkClientTrusted(certificates, authType); } /** * @see javax.net.ssl.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 javax.net.ssl.X509TrustManager#getAcceptedIssuers() */ public X509Certificate[] getAcceptedIssuers() { return this.standardTrustManager.getAcceptedIssuers(); } }
Y agregué este método: getNewHttpClient ()
public static HttpClient getNewHttpClient() { 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.UTF_8); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); return new DefaultHttpClient(ccm, params); } catch (Exception e) { return new DefaultHttpClient(); } }
Finalmente para cada lugar en mi código que tenía:
DefaultHttpClient client = new DefaultHttpClient();
Lo reemplazo por:
HttpClient client = getNewHttpClient();
Aquí está una solución de HttpsUrlConnection POST de Android completa con pinning de certificado, código del lado del servidor de tiempo de espera y configuraciones.
La variable params
debe estar en el formulario username = demo & password = abc123 &.
@Override public String sendHttpRequest(String params) { String result = ""; try { URL url = new URL(AUTHENTICATION_SERVER_ADDRESS); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(KeyPinStore.getInstance().getContext().getSocketFactory()); // Tell the URLConnection to use a SocketFactory from our SSLContext connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setConnectTimeout(10000); connection.setReadTimeout(10000); PrintWriter out = new PrintWriter(connection.getOutputStream()); out.println(params); out.close(); BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()), 8192); String inputLine; while ((inputLine = in.readLine()) != null) { result = result.concat(inputLine); } in.close(); //} catch (IOException e) { } catch (IOException | KeyStoreException | CertificateException | KeyManagementException | NoSuchAlgorithmException e) { result = e.toString(); e.printStackTrace(); } return result; }
- ¿Puede una aplicación Android instalar otra aplicación para Android?
- Cómo pasar Drawable usando Parcelable