当前位置: 首页 > article >正文

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


http://www.kler.cn/a/133601.html

相关文章:

  • Oracle 单机及 RAC 环境 db_files 参数修改
  • 【Excel】身份证号最后一位“X”怎么计算
  • zabbix搭建钉钉告警流程
  • 从华为到创业公司
  • MFC工控项目实例二十九主对话框调用子对话框设定参数值
  • jmeter介绍、使用方法、性能测试、现参数化和数据驱动、分布式测试、压力测试、接口测试
  • 一文了解ChatGPT Plus如何完成论文写作和AI绘图
  • rust内存优化
  • .NET CLR介绍
  • 处理多个axios请求
  • Hive 定义变量 变量赋值 引用变量
  • centos 安装 docker
  • echarts双轴刻度线y轴刻度线对齐
  • 支持4KHz回报还能无线充电,简约不简单的雷柏VT3S游戏鼠标上手
  • Mongodb 副本集名称重命名
  • Vue3 动态设置 ref
  • 2018年五一杯数学建模C题江苏省本科教育质量综合评价解题全过程文档及程序
  • 使用html2canvas转换table为图片时合并单元格rowspan失效,无边框显示问题解决(React实现)
  • python从基础到UnitTest框架-python基础语法
  • iOS_折叠展开 FoldTextView
  • 手机LiDAR-based激光雷达标定板提高无人汽车智能化程度
  • Nas搭建webdav服务器并同步Zotero科研文献
  • 持续集成部署-k8s-配置与存储-配置管理:SubPath
  • 新版JetBrains ToolBox【Windows】修改应用安装位置
  • Node.js之path路径模块
  • ubuntu22.04换源