HTTPS GET (SSL) with Android and self-signed server certificate
I have looked into various posts about how to retrieve something via HTTPS
on Android, from a server that uses a self-signed certificate. However, none of them seem to work - they all fail to remove the
javax.net.ssl.SSLException: Not trusted server certificate message.
It is not an option to modify the server to have a trusted certificate, and it is also not an option to make the server certificate match the server's IP address.
Note, that the server will not have a DNS name, it will only have an IP-address. The GET request looks something like this:
https://username:password@anyIPAddress/blabla/index.php?param=1¶m2=3
I am fully aware that this soluti开发者_如何转开发on is prone to man-in-the-middle attacks etc.
So, the solution must ignore the lack of trust in the certificate, and ignore the hostname mismatch.
Does anybody know the code, that does this, using Java for Android?
There are plenty of attempts to explain this on stackoverflow.com, and plenty of code snippets, but they don't seem to work, and nobody has provided one block of code that solves this, as far as I can see. It would be interesting to know if somebody really solved this, or if Android simply blocks certificates that are not trusted.
As you correctly point out, there are two issues: a) the certificate isn't trusted, and b) the name on the certificate doesn't match the hostname.
WARNING: for anybody else arriving at this answer, this is a dirty, horrible hack and you must not use it for anything that matters. SSL/TLS without authentication is worse than no encryption at all - reading and modifying your "encrypted" data is trivial for an attacker and you wouldn't even know it was happening.
Still with me? I feared so...
a) is solved by creating a custom SSLContext whose TrustManager accepts anything:
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] {
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
}
}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
and b) by creating a HostnameVerifier which allows the connection to proceed even though the cert doesn't match the hostname:
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
Both must happen right at the beginning of your code, before you start messing around with HttpsURLConnections and so on. This works both in Android and the regular JRE. Enjoy.
I made an app that uses self-signed or trust all certs. The source is here and free to use :P
Just use the HttpManager and create the SSL factory using the trust all one. Sample code found here.
If you're using an HttpsURLConnection, then try calling setHostnameVerifier
on it before connect()
, and passing it a HostnameVerifier
that just accepts regardless of veracity.
You can do it quiet securely: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
If you have an access to the devices you can add the certificate to a keystore. See more informations here.
On the other hand you can use this method, but I think it's kind of ugly.
Resources :
- developer.android.com - SSLSocketFactory
- Android and self-signed ssl certificates
On the same topic :
- Https Connection Android
- HTTPS with Self-Signed SSL Certificate Issues… Solution or better way?
- Self Signed SSL acceptance Android
If you ask me, do it the secure way.
Found a good tutorial http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/ and it's really not that difficult to implement.
Also the tutorial recommended by Maciek is very good.
I tested it, and it works in my app without problems.
I made an app that uses self-signed certificate 4 month ago here is the code i hope it helps: https://bitbucket.org/momo0002/tlsdemo.git
精彩评论