Android:使用HttpsURLConnection的HTTPS(SSL)连接
我有2个应用程序,一个是Servlet/Tomcat服务器,另一个是Android应用程序。Android:使用HttpsURLConnection的HTTPS(SSL)连接
我想使用HttpURLConnection在两者之间发送和接收XML。
代码:
private String sendPostRequest(String requeststring) {
DataInputStream dis = null;
StringBuffer messagebuffer = new StringBuffer();
HttpURLConnection urlConnection = null;
try {
URL url = new URL(this.getServerURL());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
out.write(requeststring.getBytes());
out.flush();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
dis = new DataInputStream(in);
int ch;
long len = urlConnection.getContentLength();
if (len != -1) {
for (int i = 0; i < len; i++)
if ((ch = dis.read()) != -1) {
messagebuffer.append((char) ch);
}
} else {
while ((ch = dis.read()) != -1)
messagebuffer.append((char) ch);
}
dis.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
return messagebuffer.toString();
}
现在,我需要使用SSL来送个XML安全。
首先,我使用Java Keytool生成.keystore文件。
Keytool -keygen -alias tomcat -keyalg RSA
然后我把XML代码在Tomcat的server.xml文件中使用SSL
<Connector
port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="c:/Documents and Settings/MyUser/.keystore"
keystorePass="password"
clientAuth="false" sslProtocol="TLS"
/>
然后,我改变它HttpsURLConnection的
private String sendPostRequest(String requeststring) {
DataInputStream dis = null;
StringBuffer messagebuffer = new StringBuffer();
HttpURLConnection urlConnection = null;
//Conexion por HTTPS
HttpsURLConnection urlHttpsConnection = null;
try {
URL url = new URL(this.getServerURL());
//urlConnection = (HttpURLConnection) url.openConnection();
//Si necesito usar HTTPS
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
//Creo la Conexion
urlHttpsConnection = (HttpsURLConnection) url.openConnection();
//Seteo la verificacion para que NO verifique nada!!
urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY);
//Asigno a la otra variable para usar simpre la mism
urlConnection = urlHttpsConnection;
} else {
urlConnection = (HttpURLConnection) url.openConnection();
}
//Do the same like up
的HttpURLConnection类,并添加trustAllHosts方法信任每台服务器(不检查任何证书)
private static void trustAllHosts() {
X509TrustManager easyTrustManager = new X509TrustManager() {
public void checkClientTrusted(
X509Certificate[] chain,
String authType) throws CertificateException {
// Oh, I am easy!
}
public void checkServerTrusted(
X509Certificate[] chain,
String authType) throws CertificateException {
// Oh, I am easy!
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
这些改变非常好,但我不想信任每台服务器。我想用我的密钥库文件来验证连接并以正确的方式使用SSL。 我在网上阅读了很多,并做了很多测试,但我不明白我必须做什么以及如何去做。
有人可以帮我吗?
非常感谢您
对不起,我的英文不好
------------------------- UPDATE 2011/08/24 ------------------------------------------------ -
嗯,我仍在为此工作。我做了一个新的方法来设置密钥存储的InputStream等
的方法是这样的:
private static void trustIFNetServer() {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
String keyPassword = "password";
ks.load(in, keyPassword.toCharArray());
in.close();
tmf.init(ks);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, tms, new java.security.SecureRandom());
} catch (Exception e) {
e.printStackTrace();
}
}
首先,我有很多与密钥和证书的问题,但现在它是工作(我认为是)
我现在的问题是TimeOut异常。我不知道它为什么产生。我认为这是写数据的东西,但我还不能解决。
任何想法?
您需要为here所述的自签名证书创建一个信任存储文件。 在客户端使用它来连接您的服务器。如果你使用JKS或其他格式并不重要,我现在将假设JKS。
为了实现你的想法,显然你需要不同的TrustManager
。您可以使用TrustManagerFactory
并将其信任设置与新创建的信任库一起提供。
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("<path to your key store>");
ks.load(in, "password".toCharArray());
in.close();
tmf.init(ks);
TrustManager[] tms = tmf.getTrustManagers();
使用tms
来初始化你SSLContext
而不是为用于您的SSL/TLS连接新的信任设置。
此外,您应该确保服务器TLS证书的CN
部分等于您服务器的FQDN(完全限定的域名),例如,如果您的服务器的基本URL是'https://www.example.com',那么证书的CN
应该是'www.example.com'。这是主机名验证所必需的,该功能可防止中间人攻击。您可以禁用此功能,但只有在使用此连接时才会非常安全。
我认为他需要正确配置android客户端的truststore,而不是服务器。 –
你是对的 - 我会改变这一点,谢谢! – emboss
感谢您的帮助。我会尽力了解所有这些,并进行一些测试。非常感谢你! –
创建您的信任存储,作为资产存储并使用它初始化此SocketFactory。然后用工厂代替你自己的'相信每个人'。
谢谢,你有一些例子吗? –
不是一个完整的例子,但是一旦你加载了你的信任存储(其中包含服务器证书),只需将它与密码一起传递给构造函数即可。然后,您可以将生成的'SocketFactory'实例传递给'HttpsURLConnection.setDefaultSSLSocketFactory()'。 –
是否使用由知名认证机构签署的证书或您使用自签名的证书? –