• 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都有点懵,所以写个文章供以后查阅

  • 相关阅读:
    Spring中@Bean标注的方法是如何创建对象呢?
    spring boot 中的异步@Async
    基于SSM的概念可视化程序设计学习系统毕业设计源码021009
    豪恩集团IPO过会:年营收9.8亿 应收账款价值超2亿
    VS2015 Winform 添加文件后 中文乱码
    面试官:你说说一条查询 SQL 的执行过程
    从 React 源码彻底搞懂 Ref 的全部 api
    19.1 STL总述、发展史、组成与数据结构谈
    从0开始在Vscode中搭建Vue2/3项目详细步骤
    C#中的方法
  • 原文地址:https://blog.csdn.net/franzhong/article/details/134472488