如果服务器是https的,访问受限怎么办?有两种方法,一种是接受一切证书个人官方正式非正式,当然这样就牺牲了安全性,网上方法很多,我现在教大家如何去验证crt文件
首先服务器是https的,必然有几个文件,比方说apache版本的就有xx.key xx.chain.crt xx.public.crt,没有这三个文件,你是不搞不出来https的,这是官方申请来的文件,具有权威性
当然几个文件都有作用包括CA认证的,我这次只用到public.crt文件
1、首先将文件copy到工程的raw文件夹下,稍后引用
这里说一下设置Setting里也有一个载入accepted certificates(不知道在设置顶上可以搜),里面也可以引入,时间有现我就试了一下,发现不行就没试,估计还有别的地方要改,这块本文暂不涉及
2、验证权限要在所有访问之前
比如App启动的时候,或者在登录的时候,由于要用到一个Context要传过来要用它去找文件,所以我把他放在登录里调用一次即可,核心内容-TrustManager;
public static void handleSSLHandshake(Context cont) { try { InputStream inputStream = cont.getResources().openRawResource(R.raw.web_public);//这就是开头raw里的文件 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream); // 创建信任管理器并添加证书 TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { final X509Certificate[] x509Certificates = new X509Certificate[]{certificate}; return x509Certificates; // 返回包含您的证书的数组 } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { // 在这里进行您的自定义验证逻辑,例如检查证书颁发机构、有效期等 //No Used } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { // 在这里进行您的自定义验证逻辑,例如检查证书颁发机构、有效期等 // 如果更换证书,此处需要修改 for (X509Certificate cert : certs) { if (!cert.getIssuerDN().getName().equals("CN=companyname,OU=www.domain.com,O=DigiCert Inc,C=US")) { //Log.d("TAG",cert.getIssuerDN().getName());//查看把上一步改为你自已的 throw new CertificateException("Invalid server certificate"); } if (cert.getNotBefore().after(new Date())) { throw new CertificateException("Server certificate not valid before " + cert.getNotBefore()); } if (cert.getNotAfter().before(new Date())) { throw new CertificateException("Server certificate not valid after " + cert.getNotAfter()); } } } }}; // 创建SSL上下文并初始化信任管理器 SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new SecureRandom()); // 设置默认的SSL套接字工厂和主机名验证器 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; // 可以根据需要更改主机名验证逻辑 } }); } catch (Exception e) { e.printStackTrace(); } }
这里面可验证的东西很多,包括公司名、国家、有效期等等,可以做到一项有不一致立马拒绝,提升安全性。但是我要说一下:
1)checkClientTrusted checkServerTrusted这两个区别,如果你只是访问https接口的话,其实只有checkServerTrusted起作用,另一个是反向的验证,有机会的可以测试一下;
2)import包含部分,哪里提示红色的直接按提示去包含个包就好了,没有非标准库的内容,放心使用;
3)参数Context是上下文,目的是找文件路径的,如果你在Main或Activity中调用,直接给个this或都MyActivity.this,这个大家都会。
4)一定要加上网络权限,别忘了-androidmanifest
关于android高版本,9.0你可能需要增加一条策略,否则容易报错,一般错误都会定位在:
DataOutputStream wr = new DataOutputStream(con.getOutputStream());这个附近,如果一直报错,说明版本高了,安全策略变了,执行下面几句话即可:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); }//如果报错,这几句也要独立执行一下,放代码前头
你可以运行handleSSLHandshake(MyActivity.this)了;至此握手工作已经完成。
接下来提供点https远程接口的访问模板,供大家改着用
try { URL obj = new URL("https://mydomain.com/api"); HttpsURLConnection con = (HttpsURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); con.setRequestProperty("Authorization", "testMe"); String bodyParams = "param1=" + "test123"; con.setDoOutput(true); DataOutputStream wr = new DataOutputStream(con.getOutputStream()); wr.writeBytes(bodyParams); wr.flush(); wr.close(); int responseCode = con.getResponseCode(); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); Log.i("TAG", URLDecoder.decode(response.toString(), "UTF-8")); } catch (IOException e) { e.printStackTrace(); }
这样就能该问远程接口了,本地会输出一个Log远程返回值,如果你把网址换了,就会提示握手错误,防劫持防攻击,让更加安全,更多内容看里面注释,祝你成功!
说句心里话,这玩意是很繁琐,是难者不会会者不难的事,细心按我说的来,会成功的,网上大部分不准的,太多针对老版本,很难解决问题,调试的Bug,连AI都有点懵,所以写个文章供以后查阅