Android面试题-Java安全专题七

作者: 小怪兽打葫芦娃 | 来源:发表于2017-06-08 09:17 被阅读392次

    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面试题-Java安全专题七

      本文链接:https://www.haomeiwen.com/subject/gdezfxtx.html