用了Https防抓包就真的安全了?带你领会其中奥秘

2022-8-22 10:52| 发布者: 17111881158| 查看: 1777| 评论: 0

这里是默认签名
HTTPS的定义

简而言之,HTTPS可以理解为HTTP+TLS,TLS是传输层加密协议,是HTTPS安全的核心,其前身是SSL 。通过对数据传输层进行加密,可以有效防止被第三方黑客、抓包软件截获后解密的行为,从而极大地保护了用户访问网络的安全性。

  • 数据明文传输,易嗅探
  • 数据完整性无验证,易篡改
  • 网站身份无认证,易假冒





HTTPS工作原理

大家可能都听说过 HTTPS 协议之所以是安全的是因为 HTTPS 协议会对传输的数据进行加密,而加密过程是使用了非对称加密实现。
但其实,HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。
HTTPS 的整体过程分为证书验证和数据传输阶段,具体的交互过程如下:



证书验证阶段:

  • 浏览器发起 HTTPS 请求。
  • 服务端返回 HTTPS 证书。
  • 客户端验证证书是否合法,如果不合法则提示告警。
数据传输阶段:

  • 当证书验证合法后,在本地生成随机数。
  • 通过公钥加密随机数,并把加密后的随机数传输到服务端。
  • 服务端通过私钥对随机数进行解密。
  • 服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输。
单向/双向验证

服务器是使用的HTTPS协议传输,并且买了权威机构的CA证书。但是客户端在发送请求时,未使用证书验证方式,这样就会存在中间人攻击的可能。所以说之前我的那种做法是不安全的。
单向验证

单向认证:保证server是真的,通道是安全的(对称密钥),校验证书,不可以抓包。
流程:

1.客户端向服务器端发送SSL协议版本号、加密算法种类、随机数等信息。
2.服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书。
3.客户端使用服务端返回的信息验证服务器的合法性,包括

  • 证书是否过期
  • 发行服务器证书的CA是否可靠
  • 返回的公钥是否能正确解开返回证书中的数字签名
  • 服务器证书上的域名是否和服务器的实际域名相匹配
  • 验证通过后,将继续进行通信,否则,终止通信
4.客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择。
5.服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
6.服务器将选择好的加密方案通过明文方式返回给客户端。
7.客户端接收到服务器端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的秘钥,使用服务器端返回的公钥进行加密,将加密后的随机码发送至服务器。
8.服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密秘钥。
9.在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
准备

向我们亲爱的后台小伙伴要下他们申请的证书,.crt或者.pem的都可以,然后转成.cer证书,将.cer文件导入工程。



在*AFHTTPSessionManager中按照上图进行写。注意AFHTTPSessionManager要用initWithBaseURL初始化,这样,单项验证就完了。*
双向验证

保证client和server是真的,通道是安全的(对称密钥)
流程

1.客户的浏览器向服务器传递客户端SSL协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。
2.服务器向客户端传送SSL协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。
3.客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括

  • 证书是否过期
  • 发行服务器证书的CA是否可靠
  • 发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”
  • 服务器证书上的域名是否和服务器的实际域名相匹配
  • 如果合法性验证没有通过,通讯将断开,如果合法性验证通过,将继续进行第四步。
4.用户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤2终端服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。
5.如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。
6.如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:
客户的证书使用日期是否有效
为客户提供证书的CA是否可靠
发行CA的公钥能否正确解开客户证书的发行CA的数字签名
检查客户的证书是否在证书废止列表(CRL)中。
检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。
7.服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于SSL协议的安全数据通讯的加解密通讯。同时在SSL通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。
8.客户端向服务器端发出信息,指明后面的数据通讯将使用步骤7中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。
9.服务器向客户端发出信息,指明后面的数据通讯将使用的步骤7中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。
10.SSL的握手部分结束,SSL安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。
双向验证的实例代码:






一般应用都是采用单向认证的,原因很简单,用户数目广泛,且无需做在通讯层做用户身份验证,一般都在应用逻辑成来保护用户的合法登入。但如果是企业对应对接,情况就不一样,可能会要求对客户端做身份验证。这时就需要做双向认证。
差异:从单向认证和双向认证的流程来看,单向认证只要求站点部署了SSL证书就行,任何用户都可以去访问(IP被限制除外等),只是服务器端提供了身份认证。而双向认证则是需要服务端需要客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对要高一些。
常用抓包工具


  • Charles
  • Fiddler
如何防止抓包

对于HTTPS API接口,如何防止抓包呢?既然问题出在证书信任问题上,那么解决方法就是在我们的APP中预置证书。在TLS/SSL握手时,用预置在本地的证书中的公钥校验服务器的数字签名,只有签名通过才能成功握手。由于数字签名是使用私钥生成的,而私钥只掌握在我们手上,中间人无法伪造一个有效的签名,因此攻击失败,无法抓包。
这样做虽然解决了抓包问题,但是也带来了另外一个问题:我们购买的证书都是有有效期的,到期前需要对证书进行更新。主要有两种方式:
1、提供预置证书更新接口。在当前证书快过期时,APP请求获取新的预置证书,这过渡时期,两个证书同时有效,直到安全完成证书切换。这种方式有一定的维护成本,且不易测试。 2、在APP中只预埋公钥,这样只要私钥不变,即使证书更新也不用更新该公钥。但是,这样不太符合周期性更新私钥的安全审计需求。一个折中的方法是,一次性预置多个公钥,只要任意一个公钥验证通过即可。考虑到我们的证书一般购买周期是3-5年,那么3个公钥,可以使用9-15年,同时,我们在此期间还可以发布新版本废弃老公钥,添加新公钥,这样可以使公钥一直更新下去。
防止抓包全过程

Android中如何访问HTTPS呢,其实Retrofit、OkHttp均支持HTTPS的访问 项目中引入网络库,以implementation 'com.squareup.okhttp3:okhttp:4.2.0'为例,
final OkHttpClient okHttpClient = new OkHttpClient.Builder().build();final Request request = new Request.Builder()        .url("https://www.baidu.com/robots.txt")        .build();final Response execute = okHttpClient.newCall(request).execute();final String bodyStr = execute.body().string();Log.d(TAG, bodyStr);复制代码那如果关闭客户端的CA证书,GlobalSign Root CA-R1,相当于不信任百度服务器的数字证书,会导致报错
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. 通过手动将GlobalSign Root CA-R1.cer放入项目中的assets文件夹,则可避免这一错误,如何引用项目中集成的证书呢? 通过
SSLContext sslContext;        try {            InputStream inputStream = getAssets().open("");            sslContext = SSLContext.getInstance("TLS");            sslContext.init(null, new TrustManager[]{OkhttpU.trustManagerForCertificates(inputStream)}, null);            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();            OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory, OkhttpU.trustManagerForCertificates(inputStream)).build();            final Request request = new Request.Builder()                    .url("https://www.baidu.com/robots.txt")                    .build();            final Response execute = okHttpClient.newCall(request).execute();            final String bodyStr = execute.body().string();            Log.d(TAG, bodyStr);        } catch (Exception e) {            e.printStackTrace();        }复制代码public class OkhttpU {    public static X509TrustManager trustManagerForCertificates(InputStream in)            throws GeneralSecurityException {        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");        Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);        if (certificates.isEmpty()) {            throw new IllegalArgumentException("expected non-empty set of trusted certificates");        }        // Put the certificates a key store.        char[] password = "password".toCharArray(); // Any password will work.        KeyStore keyStore = newEmptyKeyStore(password);        int index = 0;        for (Certificate certificate : certificates) {            String certificateAlias = Integer.toString(index++);            keyStore.setCertificateEntry(certificateAlias, certificate);        }        // Use it to build an X509 trust manager.        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(                KeyManagerFactory.getDefaultAlgorithm());        keyManagerFactory.init(keyStore, password);        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(                TrustManagerFactory.getDefaultAlgorithm());        trustManagerFactory.init(keyStore);        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {            throw new IllegalStateException("Unexpected default trust managers:"                    + Arrays.toString(trustManagers));        }        return (X509TrustManager) trustManagers[0];    }    private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {        try {            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());            InputStream in = null; // By convention, 'null' creates an empty key store.            keyStore.load(in, password);            return keyStore;        } catch (IOException e) {            throw new AssertionError(e);        }    }}复制代码就可以正常访问https了
综上,通过引入自定义证书,然后给OkHttp设置sslSocketFactory可以有效的防止抓包,但是.cer放到assets下很容易被反编译,可以通过jdk下的命令keytool -printcert -rfc -file srca.cer导出字符串,然后通过
OkHttpClientManager.getInstance()                .setCertificates(new Buffer()                        .writeUtf8(CER_STRING) //CER_STRING是到处的string常量                        .inputStream());总结

总的来说https把流量加密了,正常抓包,你看到的内容是一堆乱码。 https的加密没有安全问题,但它只是用来防止通信过程中被第三方获取明文。如果黑客能直接控制通信的双方(你的电脑,或服务器),那么黑客肯定能看到https明文的。
Android技术交流与资料学习,私信发送:核心笔记或手册即可获取!
放抓包策略就是对抗hook,常见方法:

  • 检测hook : 检测Xposed、Frida、Substrate等Hook框架
  • 使用socket连接 : 使用Socket走TCP/UDP,防止被应用层抓包
  • 传输数据加密 :协议字段加密传输,并隐藏秘钥,应用层加固
  • native层传输 : 将网络传输逻辑写到jni层实现,提高反编译门槛
这里是默认签名
回复

使用道具 举报

上一篇:寓言故事两则

下一篇:儿童寓言故事|《了不起的屎壳郎》

sitemap.txt | sitemap.xml | sitemap.html |Archiver|手机版|小黑屋|彩虹邦人脉系统 ( 皖ICP备2021012059号 )

GMT+8, 2024-11-23 08:56 , Processed in 0.252144 second(s), 49 queries .

快速回复 返回顶部 返回列表