Android studio访问选程https接口(.crt handshake)

如果服务器是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都有点懵,所以写个文章供以后查阅

你可能感兴趣的:(https,网络协议,http)