Android面试题-Java安全专题七

Android程序员面试宝典

安全专题

自定义控件

联网

工具

数据库

源码分析相关面试题

Activity相关面试题

Service相关面试题

与XMPP相关面试题

与性能优化相关面试题

与登录相关面试题

与开发相关面试题

与人事相关面试题

1.7 Https编程

1.7.1 介绍

SSL(Secure Sockets Layer 安全套接层),为网景公司(Netscape)所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取及窃听。一般通用之规格为40 bit之安全标准,美国则已推出128 bit之更高安全标准,但限制出境。只要3.0版本以上之I.E.或Netscape浏览器即可支持SSL。

TLS(Transport Layer Security传输层安全),用于在两个通信应用程序之间提供保密性和数据完整性。TLS是SSL的标准化后的产物,有1.0 ,1.1 ,1.2三个版本,默认使用1.0。TLS1.0和SSL3.0几乎没有区别 ,事实上我们现在用的都是TLS,但因为历史上习惯了SSL这个称呼。

SSL通信简单图示:

SSL通信详细图示:

当请求使用自签名证书的网站数据时,例如请求12306的客运服务页面:https://kyfw.12306.cn/otn/
则会报下面的错误,原因是客户端的根认证机构不能识别该证书
错误信息:unable to find valid certification path to requested target

1.7.2 解决方案1

一个证书可不可信,是由TrustManager决定的,所以我们只需要自定义一个什么都不做的TrustManager即可,服务器出示的所有证书都不做校验,一律放行。

public static void main(String[] args) throws Exception {
    //协议传输层安全TLS(transport layer secure)
    SSLContext sslContext = SSLContext.getInstance("TLS");
    //创建信任管理器(TrustManager负责校验证书是否可信)
    TrustManager[] tm = new TrustManager[]{new EmptyX509TrustManager()};
    /使用自定义的信任管理器初始化SSL上下文对象
    sslContext.init(null, tm, null);
      //设置全局的SSLSocketFactory工厂(对所有ssl链接都产生影响)
      HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());         
    //URL url = new URL("https://www.baidu.com");
    URL url = new URL("https://kyfw.12306.cn/otn/");
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    InputStream in = conn.getInputStream();
    System.out.println(Util.inputstream2String(in));
    }       
    /**
     * 自定义一个什么都不做的信任管理器,所有证书都不做校验,一律放行
    */
    private static class EmptyX509TrustManager implements X509TrustManager{
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
    }
    @Override
    public X509Certificate[] getAcceptedIssuers() {return null;
    }           
}

1.7.3 解决方案2

12306服务器出示的证书是中铁集团SRCA给他颁发的,所以SRCA的证书是能够识别12306的证书的,所以只需要把SRCA证书导入系统的KeyStore里,之后交给TrustManagerFactory 进行初始化,则可把SRCA添加至根证书认证机构,之后校验的时候,SRCA对12306证书校验时就能通过认证。
这种解决方案有两种使用方式:一是直接使用SRCA.cer文件,二是使用改文件的RFC格式数据,将其写在代码里。

//12306证书的RFC格式(注意要记得手动添加两个换行符)
private static final String CERT_12306_RFC = "-----BEGIN CERTIFICATE-----\n"
+ "MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn"
+ "BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X"
+ "DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp"
+ "bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3"
+ "DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2"
+ "9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6"
+ "D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle"
+ "tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov"
+ "LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt"
+ "x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV"
+ "23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ"
+ "og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A=="
+ "-----END CERTIFICATE-----\n";
public static void main(String[] args) throws Exception {
    // 使用传输层安全协议TLS(transport layer secure)
    SSLContext sslContext = SSLContext.getInstance("TLS");
    //使用SRCA.cer文件的形式
    //FileInputStream certInputStream = new FileInputStream(new File("srca.cer"));
    //也可以通过RFC字符串的形式使用证书
    ByteArrayInputStream certInputStream = new ByteArrayInputStream(CERT_12306_RFC.getBytes());
    // 初始化keyStore,用来导入证书
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    //参数null表示使用系统默认keystore,也可使用其他keystore(需事先将srca.cer证书导入keystore里)
    keyStore.load(null);
    //通过流创建一个证书
    Certificate certificate = CertificateFactory.getInstance("X.509")
                    .generateCertificate(certInputStream);
    // 把srca.cer这个证书导入到KeyStore里,别名叫做srca
    keyStore.setCertificateEntry("srca", certificate);
    // 设置使用keyStore去进行证书校验
    TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);
    //用我们设定好的TrustManager去做ssl通信协议校验,即证书校验
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
                    .getSocketFactory());
    URL url = new URL("https://kyfw.12306.cn/otn/");
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    InputStream in = conn.getInputStream();
    System.out.println(Util.inputstream2String(in));
}

1.7.4 Android里的https请求 :

把scra.cer文件考到assets或raw目录下,或者直接使用证书的RFC格式,接下来的做法和java工程代码一样

  • 欢迎关注微信公众号、长期为您推荐优秀博文、开源项目、视频

  • 微信公众号名称:Android干货程序员

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 122,709评论 15 534
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    会飞的鱼69阅读 20,522评论 18 385
  • 在刚刚结束的多特蒙德客场对战不莱梅中,老将魏登费勒顶替受伤的门将布尔基上场,表现出色。赢得了冬歇期后首场联赛的胜利...
    黄轩励阅读 189评论 0 3
  • 文/若杉 1、 周末, 和朋友在咖啡厅小聚。 朋友突然问我:“ 杉,你有没有觉得我们现在的生活,离当初的梦想越来越...
    若杉阅读 575评论 9 18
  • 儿子昨晚吵着非要吃上晓记早餐的驴肉包子。无奈起个大早给这个小祖宗去买了回来。 这个清晨很是清冷,迎面吹来的风...
    陌诺流年阅读 177评论 6 9