使用 Android Volley 发出 HTTPS 请求

Posted

技术标签:

【中文标题】使用 Android Volley 发出 HTTPS 请求【英文标题】:Making a HTTPS request using Android Volley 【发布时间】:2013-06-07 09:39:22 【问题描述】:

我正在尝试使用此代码发出 https 请求:

RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
request = new Request<String>(Request.Method.GET,"https://devblahblahblah.com/service/etc",errListener);

但我收到此错误:

com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException:信任锚 找不到证书路径。

需要注意的两点:

    HTTPS 证书有效。轻松打开,不会在浏览器上发出任何警告。 以上代码适用于 HTTP 链接。

我实际上需要知道 Android Volley 框架中是否有任何开关/选项,我可以通过这些开关/选项成功访问 HTTPS URL?

【问题讨论】:

我猜你需要像直接使用HttpUrlConnection一样配置它。见commonsware.com/blog/2013/03/04/ssl-android-basics.html 和nelenkov.blogspot.ie/2011/12/… 我找到了一个名为HurlStack 的类,它扩展了HttpStack,这是Volley.newRequestQueue 的可选参数。 HurlStack 的构造函数接受 SSLSocketFactory 类型的参数,它写在它的 javadoc 中:“用于 HTTPS 连接的 SSL 工厂”,但还没有尝试过。 【参考方案1】:

警告:以下代码不应在生产中使用,因为它容易受到 SSL 攻击

下面的这些代码可能会对您有所帮助:

1.创建一个实现X509TrustManagerHttpsTrustManager类:

public class HttpsTrustManager implements X509TrustManager 

    private static TrustManager[] trustManagers;
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[];

    @Override
    public void checkClientTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException 

    

    @Override
    public void checkServerTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException 

    

    public boolean isClientTrusted(X509Certificate[] chain) 
        return true;
    

    public boolean isServerTrusted(X509Certificate[] chain) 
        return true;
    

    @Override
    public X509Certificate[] getAcceptedIssuers() 
        return _AcceptedIssuers;
    

    public static void allowAllSSL() 
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() 

            @Override
            public boolean verify(String arg0, SSLSession arg1) 
                return true;
            

        );

        SSLContext context = null;
        if (trustManagers == null) 
            trustManagers = new TrustManager[]new HttpsTrustManager();
        

        try 
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
         catch (NoSuchAlgorithmException e) 
            e.printStackTrace();
         catch (KeyManagementException e) 
            e.printStackTrace();
        

        HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    


2.在发出https请求之前添加HttpsTrustManager.allowAllSSL()

HttpsTrustManager.allowAllSSL();
String  tag_string_req = "string_req";
StringRequest strReq = new StringRequest(Request.Method.POST,
        your_https_url, new Response.Listener<String>() 
    @Override
    public void onResponse(String response) 
        Log.d(TAG, "response :"+response);
    
, new Response.ErrorListener() 
    @Override
    public void onErrorResponse(VolleyError error) 
        VolleyLog.d(TAG, "Error: " + error.getMessage());
    
)
    @Override
    protected Map<String, String> getParams() 
        Map<String, String> params = new HashMap<String, String>();
        params.put("username", "max");
        params.put("password", "123456");
        return params;
    
;
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);

【讨论】:

这一切都很好,只是您实际上并没有验证服务器证书。请确保不要将其部署在生产环境中,除非您想让您的用户遭受各种 SSL 攻击。 这不是用于生产的。 这看起来像是在 localhost 上进行自签名证书的简单解决方案 如何像海报所问的那样与 Volley 一起工作? 如果您使用此应用,您的应用将在 Google Play 中被拒绝。【参考方案2】:

你可以add this class 并通过onCreate 方法执行它

new NukeSSLCerts().nuke();

它将使凌空信任所有 SSL 证书。

【讨论】:

另一种方式是certbot,提供免费的签名证书,但只有90天,我们必须每90天更新一次 完美开发 从 2017 年 3 月 1 日起,Google 可以阻止您的应用:support.google.com/faqs/answer/7188426“从 2017 年 3 月 1 日开始,Google Play 将阻止发布任何使用不安全的 HostnameVerifier 实施的新应用或更新。您发布的APK 版本将不受影响,但除非您解决此漏洞,否则应用程序的任何更新都将被阻止。” @MaxF 在我给出的第二条评论中,另一种方法。总而言之,只有在你处于开发模式时才使用 nukeSSl 类【参考方案3】:

如果你正在使用 volley 并且想要 HTTPS 请求或 SSL 认证服务,那么你可以选择这个最简单的方法:-->

步骤 --> 1. 将 .cer 文件保存到 res/raw/ 文件夹中。

步骤 --> 2. 使用此方法并将 .cer 文件名替换为您的 .cer 文件,并同时替换您的主机名。

private SSLSocketFactory getSocketFactory() 

    CertificateFactory cf = null;
    try 

        cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = getResources().openRawResource(R.raw.cert_name);
        Certificate ca;
        try 

            ca = cf.generateCertificate(caInput);
            Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
         finally 
            caInput.close();
        


        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);


        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);


        HostnameVerifier hostnameVerifier = new HostnameVerifier() 
            @Override
            public boolean verify(String hostname, SSLSession session) 

                Log.e("CipherUsed", session.getCipherSuite());
                return hostname.compareTo("10.199.89.68")==0; //The Hostname of your server.

            
        ;


        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        SSLContext context = null;
        context = SSLContext.getInstance("TLS");

        context.init(null, tmf.getTrustManagers(), null);
        HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

        SSLSocketFactory sf = context.getSocketFactory();


        return sf;

     catch (CertificateException e) 
        e.printStackTrace();
     catch (NoSuchAlgorithmException e) 
        e.printStackTrace();
     catch (KeyStoreException e) 
        e.printStackTrace();
     catch (FileNotFoundException e) 
        e.printStackTrace();
     catch (IOException e) 
        e.printStackTrace();
     catch (KeyManagementException e) 
        e.printStackTrace();
    

    return  null;

Step --> 3. 替换这一行“RequestQueue queue = Volley.newRequestQueue(this);”使用“RequestQueue queue = Volley.newRequestQueue(this, new HurlStack(null, getSocketFactory()));”应截击的要求。

【讨论】:

【参考方案4】:

到目前为止,唯一的答案是关于添加不受信任的证书作为解决方案,但由于您的浏览器没有抱怨,这通常意味着 Volley 找不到完成完整受信任链的中间证书。

LetsEncrypt 证书发生在我身上。大多数浏览器已经拥有中间证书,所以在浏览器上一切看起来都很好,但 Volley 显然缺少了一些东西。

解决方案 将中间证书添加到您的网络服务器配置中。对于 Apache,您可以参考以下参考:https://access.redhat.com/solutions/43575

对于 LetsEncrypt,具体来说就是这个文件:/etc/letsencrypt/live/your.website.com/chain.pem 因此,除了您的 CertificateFile 和 KeyFile 之外,您应该已经开始工作了,您现在有了第三行:

SSLCertificateChainFile /etc/letsencrypt/live/your.website.com/chain.pem

只需添加该行,重新启动 apache 和 Volley 就不会再抱怨了,您也没有引入任何安全漏洞!

【讨论】:

thanx,这有帮助,目前还不是很清楚我需要编辑什么文件,但我终于想通了。虽然对我来说是不同的,因为我必须在 nodejs 中进行编辑。不过谢谢。 另外,要真正追踪可能的 SSL 设置错误,您可以使用此工具测试您的网站:ssllabs.com/ssltest/index.html 如果在使用该工具后您突然沉迷于得分 A+,Mozilla 有一个有用的 SSL配置生成器:mozilla.github.io/server-side-tls/ssl-config-generator 现代风格通常让你毫无问题地达到 A+。【参考方案5】:

我无法打开@Ogre_BGR 提供的链接,但是在浏览网络时,我发现实际实现在以下smanikandan14 Github 中完成。查看他的SSl-connection explanation 以了解更多信息。

【讨论】:

【参考方案6】:

这可能有多种原因,包括:

颁发服务器证书的 CA 未知 服务器证书不是由 CA 签名的,而是自签名的 服务器配置缺少中间 CA

Official doc from android

解决方案: 您可以在请求中提供证书文件

【讨论】:

【参考方案7】:

对于遇到此类问题并且您使用 Letsencrypt 作为 SSL 和 node.js 作为网络服务器的任何人,试试这个。假设你有这样的东西。我通过添加行来解决此问题 const chain = fs... 希望这会有所帮助

...
const app = express();
const privateKey  = fs.readFileSync('ssl/privkey.pem', 'utf8');
const certificate = fs.readFileSync('ssl/cert.pem', 'utf8');
const chain = fs.readFileSync('ssl/chain.pem', 'utf8');
const credentials = key: privateKey, cert: certificate, ca: chain;
...
var httpsServer = https.createServer(credentials, app);

【讨论】:

【参考方案8】:

当我将 ssl 添加到域时,我遇到了同样的问题,经过 2 天后,我找到了 URL 错误的解决方案。我使用的是https://example.com,但是当我将 ssl 添加到域中时,url 将会改变

https://www.example.com

POST 工作正常

【讨论】:

【参考方案9】:

当我从 cloudflare 关闭代理时出现此错误 check image here 此问题的最佳解决方案是您可以打开代理返回并在 ssl 证书上添加完全安全访问。

【讨论】:

【参考方案10】:

如果有人使用nginx 和来自letsencrypt 的SSL 证书,解决方案是简单地使用来自文件fullchain.pem 的证书而不是cert.pem

ssl_certificate     /.../fullchain.pem;

此文件包含您的证书和 CA 的串联。

【讨论】:

以上是关于使用 Android Volley 发出 HTTPS 请求的主要内容,如果未能解决你的问题,请参考以下文章

仅在 Android 而非 iOS 上使用“Volley”发出的服务器请求超时

如何在 android 中使用 volley 实现 Digest 身份验证

当重试策略设置为 0 时,Android Volley 向服务器发出 2 个请求

使用 Volley 库未从 Android 收到 PHP POST

使用名称值对的 Android volley post 请求

Android Volley框架的使用