使用HttpsURLConnection的3种方法小结
2017-07-04 10:08
399 查看
最近遇到网络安全方面的问题,要将http转移到https,由于在工程中使用了HttpURLConnection,所以要相应的转而使用HttpsURLConnection,当然大部分是参考的网络上一些前辈们的成果,过程中也遇到了一些坑,在这里进行一下总结。
由于https涉及到证书的认证方式,这里简单介绍一下:
关于证书,可以简单把它理解为网站的身份证。而给网站颁发身份证的就是CA(证书颁发机构)。
可以颁发证书的CA有很多(国内外都有),只有少数CA被认为是权威、公正的,这些CA颁发的证书,浏览器、操作系统才认为是信得过的。
在Android系统中,就有一个根证书信任列表,若我们的证书是由这个列表中的某个根证书的子证书,就不需要在https使用过程中特别指定了。
我们自己也可以自己制作证书,例如使用OpenSSL就可以生成一个CA根证书,然后用这个根证书颁发两个子证书server和client,server证书放在服务器端,而这个client证书就可以用于浏览器或者安卓app中。这种自己制作的证书,就必须在app中指定了,否则https握手是不能成功的。
我就按使用证书的不同方式来进行分别说明:
1,信任系统提供的证书(权威CA颁发);
2,全部信任证书;
3,信任指定证书;
这是最简单的方式,相比较于http访问,转到https协议,只是将HttpURLConnection 替换为 HttpsURLConnection 就够了。
下面是一个使用 HttpsURLConnection 实现的POST请求:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
调用示例:
1
添加HTTPSTrustManager类,如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
再在所有https开始进行请求之前,执行一次即可:
1
后面就是正常的进行https访问就可以了:
1
先要获取到证书,我们可以放到assert目录下,例如这里使用的证书的文件名为“root.crt”。
通过如下函数来读取,并返回SSLContext:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
然后,在使用 HttpsURLConnection 的过程中,也就是httpsPostData()函数中,使用指定证书的 SSLContext 即可:
1
当然,如果仔细看了前面的 httpsPostData()函数内容的话,就知道前面的代码中已经有这句话了,只是被注释掉了。打开就可以了,就是使用指定证书的了。
至于调用POST请求的地方,是一样的:
1
1,全部信任证书:不太安全,Google也不推荐。但是毕竟是https,比http安全多了,只是还存在被中间人攻击的风险;
2,信任指定证书:这种方式保证了网络传输链路的安全,是可以防住中间人攻击的。
但是问题可能会出在App上:这个证书直接放在app中,若是由于某些原因导致证书需要更新,就需要更新所有的app,在用户量较大的情况下,这几乎是不可能完成的任务。
3,信任系统提供的证书(CA颁发);这种方式最好,既安全又好维护,更换一个CA颁发的证书,对代码不需要做任何改动,但是可能需要花钱。也可以找些免费的证书,但是使用期限可能有较大的限制。
这三种方式各有特色,具体采用哪种方式,还是需要根据自己项目的实际情况来确定。
http://blog.csdn.net/whu_zhangmin/article/details/45868057
http://www.cnblogs.com/cxjchen/p/3152832.html
原创地址:http://blog.csdn.net/lintax/article/details/70195138
由于https涉及到证书的认证方式,这里简单介绍一下:
关于证书,可以简单把它理解为网站的身份证。而给网站颁发身份证的就是CA(证书颁发机构)。
可以颁发证书的CA有很多(国内外都有),只有少数CA被认为是权威、公正的,这些CA颁发的证书,浏览器、操作系统才认为是信得过的。
在Android系统中,就有一个根证书信任列表,若我们的证书是由这个列表中的某个根证书的子证书,就不需要在https使用过程中特别指定了。
我们自己也可以自己制作证书,例如使用OpenSSL就可以生成一个CA根证书,然后用这个根证书颁发两个子证书server和client,server证书放在服务器端,而这个client证书就可以用于浏览器或者安卓app中。这种自己制作的证书,就必须在app中指定了,否则https握手是不能成功的。
我就按使用证书的不同方式来进行分别说明:
1,信任系统提供的证书(权威CA颁发);
2,全部信任证书;
3,信任指定证书;
1,信任系统提供的证书
这是最简单的方式,相比较于http访问,转到https协议,只是将HttpURLConnection 替换为 HttpsURLConnection 就够了。 下面是一个使用 HttpsURLConnection 实现的POST请求:
public static void httpsPostData(final Context context, final String urlPath, final String content){ new Thread() { @Override public void run() { // TODO Auto-generated method stub Looper.prepare(); URL url; try { url = new URL(TimeValidity.addTimeValidityUrl(urlPath)); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); //conn.setSSLSocketFactory(getSSLContext(context).getSocketFactory()); conn.setConnectTimeout(TIMEOUT_LONG);//5 conn.setReadTimeout(TIMEOUT_LONG); conn.setDoOutput(true);// 设置允许输出 conn.setRequestMethod("POST"); conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); OutputStream os = conn.getOutputStream(); os.write(content.getBytes()); os.close(); /* 服务器返回的响应码 */ int code = conn.getResponseCode(); Log.i("https","code="+code); if (code == 200) { BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); String retData = null; String responseData = ""; while ((retData = in.readLine()) != null) { responseData += retData; } in.close(); } else { Log.i("https","return error"); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } Looper.loop(); } }.start(); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
调用示例:
httpPostData(MainActivity.this, url, content);1
1
2,全部信任证书
添加HTTPSTrustManager类,如下:public class HTTPSTrustManager implements X509TrustManager { private static TrustManager[] trustManagers; private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {}; @Override public void checkClientTrusted( java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { // To change body of implemented methods use File | Settings | File // Templates. } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { // To change body of implemented methods use File | Settings | File // Templates. } @Override public X509Certificate[] getAcceptedIssuers() { return _AcceptedIssuers; } public static void allowAllSSL() { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { // TODO Auto-generated method stub return true; } }); SSLContext context = null; if (trustManagers == null) { trustManagers = new TrustManager[] { new HTTPSTrustManager() }; } try { context = SSLContext.getInstance("TLS"); context.init(null, trustManagers, new SecureRandom()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
再在所有https开始进行请求之前,执行一次即可:
HTTPSTrustManager.allowAllSSL();//信任所有证书1
1
后面就是正常的进行https访问就可以了:
httpPostData(MainActivity.this, url, content);1
1
3,信任指定证书
先要获取到证书,我们可以放到assert目录下,例如这里使用的证书的文件名为“root.crt”。 通过如下函数来读取,并返回SSLContext:
public static SSLContext getSSLContext(Context inputContext){ SSLContext context = null; try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream in = inputContext.getAssets().open("root.crt"); Certificate ca = cf.generateCertificate(in); KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(null, null); keystore.setCertificateEntry("ca", ca); String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keystore); // Create an SSLContext that uses our TrustManager context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); } catch (Exception e){ e.printStackTrace(); } return context; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
然后,在使用 HttpsURLConnection 的过程中,也就是httpsPostData()函数中,使用指定证书的 SSLContext 即可:
conn.setSSLSocketFactory(getSSLContext(context).getSocketFactory());1
1
当然,如果仔细看了前面的 httpsPostData()函数内容的话,就知道前面的代码中已经有这句话了,只是被注释掉了。打开就可以了,就是使用指定证书的了。
至于调用POST请求的地方,是一样的:
httpPostData(MainActivity.this, url, content);1
1
最后总结一下:
1,全部信任证书:不太安全,Google也不推荐。但是毕竟是https,比http安全多了,只是还存在被中间人攻击的风险;2,信任指定证书:这种方式保证了网络传输链路的安全,是可以防住中间人攻击的。
但是问题可能会出在App上:这个证书直接放在app中,若是由于某些原因导致证书需要更新,就需要更新所有的app,在用户量较大的情况下,这几乎是不可能完成的任务。
3,信任系统提供的证书(CA颁发);这种方式最好,既安全又好维护,更换一个CA颁发的证书,对代码不需要做任何改动,但是可能需要花钱。也可以找些免费的证书,但是使用期限可能有较大的限制。
这三种方式各有特色,具体采用哪种方式,还是需要根据自己项目的实际情况来确定。
参考:
http://blog.csdn.net/whu_zhangmin/article/details/45868057 http://www.cnblogs.com/cxjchen/p/3152832.html
原创地址:http://blog.csdn.net/lintax/article/details/70195138
相关文章推荐
- 使用HttpsURLConnection的3种方法小结
- 使用HttpsURLConnection发送POST请求
- 分享android的HttpURLConnection和URLConnection官方使用方法
- 使用HttpUrlConnection或者HttpClient做https请求时导致的SSLHandshakeException异常
- 关于双向认证,使用HttpsURLConnection访问Https安全链接
- 使用JDK自带HttpsURLConnection发送HTTPS请求
- J2EE 关于WebLogic下应用使用URL.openConnection获取连接返回 HttpsURLConnection与SOAPHttpsURLConnection的问题
- Android HttpUrlConnection如何使用Https连接
- require.js使用baseUrl + paths导入文件配置的3种方法
- 使用HttpsURLConnection访问https资源(自签名)
- WebLogic下使用URL.openConnection获取连接返回 HttpsURLConnection与SOAPHttpsURLConnection的问题
- HttpUrlConnection和HttpClient的使用(doGet( )、doPost( )方法)
- 使用HttpsURLConnection发送POST请求
- Volley支持https的3种方法小结
- Myeclipse下使用svn碰到Secure connection truncated (https:)解决方法
- J2EE 关于WebLogic下应用使用URL.openConnection获取连接返回 HttpsURLConnection与SOAPHttpsURLConnection的问题
- 使用HttpsURLConnection发送POST请求
- WebLogic下使用URL.openConnection获取连接返回 HttpsURLConnection与SOAPHttpsURLConnection的问题
- 使用HttpURLConnection 的post方法来返回一个xml