为了账号安全,请及时绑定邮箱和手机立即绑定

SSLHandshakeException:在Android N / 7.0上握手失败

SSLHandshakeException:在Android N / 7.0上握手失败

人到中年有点甜 2019-12-21 11:11:21
我正在开发一个应用程序,(高级)用户必须为此设置他们自己的服务器(即nginx)来运行后端应用程序。需要在应用程序中配置相应的域,以便它可以连接。我主要在自己的手机(sony z3c)上进行测试,并开始为5.1开发。后来我收到了6.0的更新,但在仿真器中仍保持有效的5.1。不久之前,我开始使用具有7.0映像的AVD进行工作,但我惊讶地发现它无法连接到服务器,并告诉我SSL握手失败。我的nginx配置非常严格,但它同时适用于5.1和6.0,所以....?!这是我所知道的:我使用v24作为支持库,即我的compileSdkVersion为24。我使用Volley v1.0.0。我已经尝试了TLSSocketFactory,但是它没有任何改变。无论如何,似乎大多数时候都使用此方法来防止将SSL3用于较早的SDK版本。我尝试增加超时时间,但是它没有任何改变。我已经尝试过直接使用HttpURLConnection,但是除了堆栈跟踪,它没有任何改变(它没有凌空引用,但是完全相同)。如果没有TLSSocketFactory,则请求是通过裸请求队列发出的,使用实例化Volley.newRequestQueue(context)。因为它说SSLV3_ALERT_HANDSHAKE_FAILURE我只能假设由于某种原因尝试使用SSLv3进行连接而失败,但这对我来说毫无意义。它可能是一个密码问题,但是我怎么知道它试图使用什么呢?我宁愿不启用服务器上的密码,进行连接尝试并重复。我的nginx站点使用一个“让我们加密”证书,并具有以下配置:ssl_stapling on;ssl_stapling_verify on;ssl_trusted_certificate /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem;ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:!aNULL;ssl_dhparam /etc/ssl/certs/dhparam.pem;ssl_ecdh_curve secp384r1;ssl_prefer_server_ciphers on;ssl_protocols TLSv1.2;为了测试这些密码,我有一个脚本,它可以确认这些密码(在服务器网络外部的微调vps上运行):测试ECDHE-RSA-AES256-GCM-SHA384 ...是测试ECDHE-ECDSA-AES256-GCM-SHA384 ...否(sslv3警报握手失败)测试ECDHE-RSA-AES256-SHA384 ... NO(sslv3警报握手失败)测试ECDHE-ECDSA-AES256-SHA384 ... NO(sslv3警报握手失败)测试ECDHE-RSA-AES256-SHA ... NO(sslv3警报握手失败)测试ECDHE-ECDSA-AES256-SHA ... NO(sslv3警报握手失败)测试SRP-DSS-AES-256-CBC-SHA ...否(sslv3警报握手失败)测试SRP-RSA-AES-256-CBC-SHA ... NO(sslv3警报握手失败)测试DHE-DSS-AES256-GCM-SHA384 ...否(sslv3警报握手失败)测试DHE-RSA-AES256-GCM-SHA384 ...否(sslv3警报握手失败)测试DHE-RSA-AES256-SHA256 ... NO(sslv3警报握手失败)测试DHE-DSS-AES256-SHA256 ... NO(sslv3警报握手失败)测试DHE-RSA-AES256-SHA ... NO(sslv3警报握手失败)测试DHE-DSS-AES256-SHA ...否(sslv3警报握手失败)测试DHE-RSA-CAMELLIA256-SHA ... NO(sslv3警报握手失败)我可以在仿真器的浏览器中打开服务器URL,并获得完美的json响应,因此我知道系统本身具有功能。所以问题是,为什么我不能在Android 7上连接?
查看完整描述

3 回答

?
波斯汪

TA贡献1811条经验 获得超4个赞

在这里,您是Volley的工作解决方案:


在以单例代码创建队列之前:


public class VolleyServiceSingleton {


    private RequestQueue mRequestQueue;

    private HurlStack mStack;


    private VolleyServiceSingleton(){


        SSLSocketFactoryExtended factory = null;


        try {

            factory = new SSLSocketFactoryExtended();

        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        } catch (KeyManagementException e) {

            e.printStackTrace();

        }



        final SSLSocketFactoryExtended finalFactory = factory;

        mStack = new HurlStack() {

            @Override

            protected HttpURLConnection createConnection(URL url) throws IOException {

                HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url);

                try {

                    httpsURLConnection.setSSLSocketFactory(finalFactory);

                    httpsURLConnection.setRequestProperty("charset", "utf-8");


                } catch (Exception e) {

                    e.printStackTrace();

                }

                return httpsURLConnection;

            }


        };




        mRequestQueue = Volley.newRequestQueue(YourApplication.getContext(), mStack, -1);    


    }



}

这是SSLSocketFactoryExtended:


public class SSLSocketFactoryExtended extends SSLSocketFactory

{

    private SSLContext mSSLContext;

    private String[] mCiphers;

    private String[] mProtocols;



    public SSLSocketFactoryExtended() throws NoSuchAlgorithmException, KeyManagementException

    {

        initSSLSocketFactoryEx(null,null,null);

    }


    public String[] getDefaultCipherSuites()

    {

        return mCiphers;

    }


    public String[] getSupportedCipherSuites()

    {

        return mCiphers;

    }


    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException

    {

        SSLSocketFactory factory = mSSLContext.getSocketFactory();

        SSLSocket ss = (SSLSocket)factory.createSocket(s, host, port, autoClose);


        ss.setEnabledProtocols(mProtocols);

        ss.setEnabledCipherSuites(mCiphers);


        return ss;

    }


    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException

    {

        SSLSocketFactory factory = mSSLContext.getSocketFactory();

        SSLSocket ss = (SSLSocket)factory.createSocket(address, port, localAddress, localPort);


        ss.setEnabledProtocols(mProtocols);

        ss.setEnabledCipherSuites(mCiphers);


        return ss;

    }


    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException

    {

        SSLSocketFactory factory = mSSLContext.getSocketFactory();

        SSLSocket ss = (SSLSocket)factory.createSocket(host, port, localHost, localPort);


        ss.setEnabledProtocols(mProtocols);

        ss.setEnabledCipherSuites(mCiphers);


        return ss;

    }


    public Socket createSocket(InetAddress host, int port) throws IOException

    {

        SSLSocketFactory factory = mSSLContext.getSocketFactory();

        SSLSocket ss = (SSLSocket)factory.createSocket(host, port);


        ss.setEnabledProtocols(mProtocols);

        ss.setEnabledCipherSuites(mCiphers);


        return ss;

    }


    public Socket createSocket(String host, int port) throws IOException

    {

        SSLSocketFactory factory = mSSLContext.getSocketFactory();

        SSLSocket ss = (SSLSocket)factory.createSocket(host, port);


        ss.setEnabledProtocols(mProtocols);

        ss.setEnabledCipherSuites(mCiphers);


        return ss;

    }


    private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)

            throws NoSuchAlgorithmException, KeyManagementException

    {

        mSSLContext = SSLContext.getInstance("TLS");

        mSSLContext.init(km, tm, random);


        mProtocols = GetProtocolList();

        mCiphers = GetCipherList();

    }


    protected String[] GetProtocolList()

    {

        String[] protocols = { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};

        String[] availableProtocols = null;


        SSLSocket socket = null;


        try

        {

            SSLSocketFactory factory = mSSLContext.getSocketFactory();

            socket = (SSLSocket)factory.createSocket();


            availableProtocols = socket.getSupportedProtocols();

        }

        catch(Exception e)

        {

            return new String[]{ "TLSv1" };

        }

        finally

        {

            if(socket != null)

                try {

                    socket.close();

                } catch (IOException e) {

                }

        }


        List<String> resultList = new ArrayList<String>();

        for(int i = 0; i < protocols.length; i++)

        {

            int idx = Arrays.binarySearch(availableProtocols, protocols[i]);

            if(idx >= 0)

                resultList.add(protocols[i]);

        }


        return resultList.toArray(new String[0]);

    }


    protected String[] GetCipherList()

    {

        List<String> resultList = new ArrayList<String>();

        SSLSocketFactory factory = mSSLContext.getSocketFactory();

        for(String s : factory.getSupportedCipherSuites()){

            Log.e("CipherSuite type = ",s);

            resultList.add(s);

        }

        return resultList.toArray(new String[resultList.size()]);

    }


}

在此代码中,我简单地添加设备支持的所有密码,对我来说这是可行的),可能会帮助某人)(干杯)


ps无需在清单中添加安全网络配置参数。


查看完整回答
反对 回复 2019-12-21
  • 3 回答
  • 0 关注
  • 875 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信