Android 应用实现 Https 双向认证

发表于 2年以前  | 总阅读数:1990 次

为什么需要双向认证

Https保证的是信道的安全,即客户端和服务端通信报文的安全。但是无法保证中间人攻击,所以双向认证解决的问题就是防止中间人攻击。

中间人攻击(Man-in-the-MiddleAttack)简称(MITM),是一种“间接”的入侵攻击,这种攻击模式是通过各种技术手段将受入侵者控制的一台计算机虚拟放置在网络连接中的两台通信计算机之间,这台计算机就称为“中间人”。若没有开启双向认证,中间人可以拦截客户端发送的请求,然后篡改信息再发送到服务端;中间人也可以拦截服务端返回的信息,再发送到客户端。所以使用Https的单向认证或双向认证能够有效防止中间人攻击。

注:无论Ca证书还是自签证书都需要双向认证。

双向认证原理

1、服务端认证客户端原理

客户端有自己的bks证书auth_client.bks,并将导出的auth_client_pub.cer证书导入到服务端证书auth_server.keystore中,这样服务端就将客户端证书添加到信任列表中,从而能够让带有该auth_client_pub.cer证书信息的客户端访问服务。

2、客户端认证服务端原理

服务端有自己的证书(ca颁发的或者是自己创建的)auth_server.keystore,并导出auth_server_pub.cer证书,将该证书导入到客户端证书

auth_truststore.jks中,注意:这里不是导入到auth_client.jks中,而是导入生成另一个证书auth_truststore.jks,最后再将jks证书转化成bks证书。

实现过程

一、服务端证书

创建服务端证书

keytool -genkeypair -alias auth_server -keyalg RSA -validity 36500 -keypass auth_server -storepass auth_server -keystore /Users/renzhongrui/android/certs/auth_server.keystore

导出服务端证书公钥

keytool -export -alias auth_server -file /Users/renzhongrui/android/certs/auth_server_pub.cer -keystore /Users/renzhongrui/android/certs/auth_server.keystore -storepass auth_server

二、客户端证书

创建客户端证书(andoird不能用keystore格式的密钥库,所以先生成jks格式,再用Portecle工具转成bks格式)

keytool -genkeypair -alias auth_client -keyalg RSA -validity 36500 -keypass auth_client -storepass auth_client -keystore /Users/renzhongrui/android/certs/auth_client.jks

导出客户端证书公钥

keytool -export -alias auth_client -file /Users/renzhongrui/android/certs/auth_client_pub.cer -keystore /Users/renzhongrui/android/certs/auth_client.jks -storepass auth_client 

三、证书交换

将客户端证书导入服务端keystore中,再将服务端证书导入客户端auth_truststore中, 一个keystore可以导入多个证书,生成证书列表。

将客户端公钥导入到服务端keystore证书中,使得服务端能够信任客户端。

keytool -import -v -alias auth_client -file /Users/renzhongrui/android/certs/auth_client_pub.cer -keystore /Users/renzhongrui/android/certs/auth_server.keystore -storepass auth_server

生成客户端信任证书库auth_truststore.jks,即将服务端公钥导入到客户端jks证书中,使得客户端能够信任服务端。

keytool -import -v -alias auth_server -file /Users/renzhongrui/android/certs/auth_server_pub.cer -keystore /Users/renzhongrui/android/certs/auth_truststore.jks -storepass auth_truststore

最后验证一下,查看证书库中的所有证书

keytool -list -keystore /Users/renzhongrui/android/certs/auth_server.keystore -storepass auth_server
keytool -list -keystore /Users/renzhongrui/android/certs/auth_truststore.jks -storepass auth_truststore

四、证书转换

下载portecle.jar(https://sourceforge.net/projects/portecle/),解压后运行jar包:-

java -jar portecle.jar

1、点击File菜单选择Open Keystore File,选择创建好的auth_client.jks或auth_truststore.jks证书,输入密码。 2、选中导入的证书,点击Tools菜单,选择Change Keystore Type,再选择BKS类型,再次输入密码,确认之后,会显示成功。 3、最后点击File菜单,选择Save Keystore File As,将证书保存的指定路径。

五、配置服务

证书准备好之后,就可以进行集成测试了,服务使用Spring Boot创建或者使用Nginx代理。

使用Spring Boot服务

1、添加配置

server:
  port: 443
  server:
    tomcat:
      uri-encoding: UTF-8
  # 开启https,配置跟证书对应
  ssl:
    key-store: classpath:auth_server.keystore
    key-store-type: JKS
    key-store-password: auth_server
    key-password: auth_server
    key-alias: auth_server
    enabled: true
    #是否需要进行认证
    client-auth: need
    protocol: TLS # 默认
    trust-store: classpath:auth_server.keystore
    trust-store-password: auth_server
    trust-store-type: JKS

2、添加代码,这里配置80端口重定向到443,也可以改成别的端口。

public class PackApplication implements WebMvcConfigurer {


    public static void main(String[] args) {
        SpringApplication.run(PackApplication.class, args);
    }


    @Bean
    public Connector connector(){
        Connector connector=new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(80);
        connector.setSecure(false);
        connector.setRedirectPort(443);
        return connector;
    }


    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector){
        TomcatServletWebServerFactory tomcat=new TomcatServletWebServerFactory(){
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint=new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection=new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(connector);
        return tomcat;
    }


}

使用Nginx服务配置

Nginx配置与Spring Boot服务配置略有不同。

server {
        listen       443;
        server_name  192.168.200.101; # 代理服务IP
        ssl on; # 开启Https


        ssl_certificate      /usr/local/nginx/conf/https/auth_server.cer; # auth_server.keystore导出的cer证书
        ssl_certificate_key  /usr/local/nginx/conf/https/auth_server.key; # auth_server.keystore导出的私钥
        ssl_client_certificate /usr/local/nginx/conf/https/auth_client.cer; # auth_client.keystore导出的cer

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
        ssl_verify_client optional; # 配置校验客户端策略,设置成optional时候可以开启白名单接口


        ssl_protocols TLSv1.1 TLSv1.2;


        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  off;


        location / { # 需要双向验证https的接口
            if ($ssl_client_verify != SUCCESS) {
                 return 401;
            }
            proxy_pass http://192.168.200.101:8008;
            proxy_connect_timeout 600;
            proxy_read_timeout 600;
        }


        location /aarm/downloadUpdateFile { # 获取证书版本和下载证书接口,不需要验证Https
            proxy_pass http://192.169.200.101:8008;
            proxy_connect_timeout 600;
            proxy_read_timeout 600;
        }
    }

六、配置客户端

在客户端app中使用OkHttp来进行网络访问,所以需要配置OkHttp来进行证书认证。

1、将上面创建的auth_client.bks和auth_truststore.bks证书放到assets目录下 2、初始化OkHttp

OkHttpClient okHttpClient = new OkHttpClient.Builder()
  .connectTimeout(10, TimeUnit.SECONDS)
  .readTimeout(10, TimeUnit.SECONDS)
  .sslSocketFactory(Https.getSSLCertifcation(getApplicationContext()))//获取SSLSocketFactory
  .hostnameVerifier(new UnSafeHostnameVerifier())//添加hostName验证器
  .build();

重点需要看一下Https类的实现:

public class Https {


    private final static String CLIENT_PRI_KEY = "auth_client.bks";
    private final static String TRUSTSTORE_PUB_KEY = "auth_truststore.bks";
    private final static String CLIENT_BKS_PASSWORD = "auth_client";
    private final static String TRUSTSTORE_BKS_PASSWORD = "auth_truststore";
    private final static String KEYSTORE_TYPE = "BKS";
    private final static String PROTOCOL_TYPE = "TLS";
    private final static String CERTIFICATE_FORMAT = "X509";


    public static SSLSocketFactory getSSLCertifcation(Context context) {
        SSLSocketFactory sslSocketFactory = null;
        try {
            // 服务器端需要验证的客户端证书,其实就是客户端的keystore
            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);// 客户端信任的服务器端证书
            KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);//读取证书
            InputStream ksIn = context.getAssets().open(CLIENT_PRI_KEY);
            InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);//加载证书
            keyStore.load(ksIn, CLIENT_BKS_PASSWORD.toCharArray());
            trustStore.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
            ksIn.close();
            tsIn.close();
            //初始化SSLContext
            SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_FORMAT);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_FORMAT);
            trustManagerFactory.init(trustStore);
            keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslSocketFactory;
    }
}

还有一个UnSafeHostnameVerifier类

private class UnSafeHostnameVerifier implements HostnameVerifier {
  @Override
  public boolean verify(String hostname, SSLSession session) {
    return true;
  }
}

此时再进行网络请求,就能够访问到带有双向认证的服务端接口了。当然一般网上的博客到这就结束了,但是这样真的就完事了吗,其实真正的设计才刚开始,如果只是了解原理,读到这里就可以了,下面才是真实应用场景。

真实场景实现

原理还是那个原理,就看怎么合理的使用了。在真实开发环境中,需要解决几个问题: auth_client.bks和auth_truststore.bks是需要动态下发的不是所有的接口都需要进行双向认证

动态下发auth_client.bks和auth_truststore.bks

1、auth_client.bks和auth_truststore.bks的制作需要在本地工具完成,然后通过管理端上传到服务器,并且改变证书的版本号; 2、客户端需要访问证书版本,来判断是否需要更新证书,如果需要更新则下载证书。

这里会引出两个问题:

1、请求版本号的接口和下载证书的接口不能进行双向认证,否则无法下发证书。 2、不进行双向认证的接口是不安全的,所以,请求版本号的接口的返回值是需要加密的;

针对第一个问题处理方式:

服务端需要配置白名单,将请求版本号的接口和下载证书的接口过滤掉;

客户端OkHttp首次初始化不能进行双向认证,等下载完证书之后,需要再次进行OkHttp初始化;

针对第二个问题处理方式:

需要本地工具创建RSA公私钥对,用于请求版本号接口的加解密;

服务端使用私钥对报文加密,客户端保存公钥,并使用公钥对报文解密。

客户端使用公钥解密后的报文格式:

{
    "version":1,
    "authType":2,
    "clientBksPath":"https://localhost/downloadUpdateFile?fileName=auth_client.bks",
    "trustBksPath":"https://localhost/downloadUpdateFile?fileName=auth_truststore.bks",
    "authKey":"auth_client"
}

version: 表示每一次更换证书的版本;

authType:0 表示不开启认证,1 表示开启单向认证,2 表示开启双向认证clientBksPath:auth_client.bks下载路径trustBksPath:auth_truststore.bks下载路径authKey:auth_client.bks证书密码客户端每次启动都要获取服务端证书版本,并将证书信息存储到本地文件或者数据库中,通过对比服务端证书版本和数据库中版本来判断是否需要证书更新。

注:这样设计的好处是当证书过期时,能够动态下发证书,但会引出一个问题,客户端要安全的存储公钥信息,一般做法是将公钥存储到so文件里,再配合应用加固手段进行保护,不过这个就不是通信安全的问题了,而是apk安全的问题。

其他证书操作

1、查看keystore证书公钥-

keytool -list -rfc --keystore release.keystore | openssl x509 -inform pem -pubkey

2、查看keystore证书私钥

先转成pfx格式

keytool -v -importkeystore -srckeystore release.keystore -srcstoretype jks -srcstorepass 123456 -destkeystore keystore/release.pfx -deststoretype pkcs12 -deststorepass 123456 -destkeypass 123456

再查看证书私钥

openssl pkcs12 -in release.pfx -nocerts -nodes

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/JKT2Ijbktv6LuIJFnrggbw

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:6月以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:6月以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:6月以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:6月以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:6月以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:6月以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:6月以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:6月以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:6月以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:6月以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:6月以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:6月以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:6月以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:6月以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:6月以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:6月以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:6月以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:6月以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:6月以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:6月以前  |  398次阅读  |  详细内容 »
 相关文章
简化Android的UI开发 4年以前  |  520650次阅读
Android 深色模式适配原理分析 3年以前  |  28543次阅读
Android阴影实现的几种方案 1年以前  |  10650次阅读
Android 样式系统 | 主题背景覆盖 3年以前  |  9518次阅读
 目录