60

我正在尝试使用以下代码发出 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:找不到证书路径的信任锚。

需要注意的两点:

  1. HTTPS 证书有效。轻松打开,浏览器上没有任何警告。
  2. 上面的代码适用于 HTTP 链接。

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

4

10 回答 10

60

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

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

1.创建一个HttpsTrustManager实现的类X509TrustManager

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());
    }

}

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

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);
于 2014-12-22T13:01:19.673 回答
16

您可以添加此类并从onCreate方法中执行它

new NukeSSLCerts().nuke();

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

于 2016-04-26T19:09:38.090 回答
5

如果您正在使用 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()));” 应凌空抽射的要求。

于 2018-02-27T13:27:38.737 回答
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 就不会再抱怨了,您也没有引入任何安全漏洞!

于 2016-12-23T14:27:46.813 回答
1

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

于 2014-05-02T14:01:48.363 回答
0

这可能有几个原因,包括:

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

来自android的官方文档

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

于 2017-02-13T08:48:59.997 回答
0

对于遇到此类问题并且您将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);
于 2019-04-29T15:14:48.913 回答
0

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

https://www.example.com

POST工作正常

于 2020-05-08T19:51:28.520 回答
0

当我从 cloudflare 关闭代理 检查图像时出现此错误 此问题的最佳解决方案是您可以重新打开代理并在 ssl 证书上添加完全安全访问。

于 2020-08-31T06:21:55.220 回答
0

如果有人使用letencrypt的nginx和 SSL 证书,解决方案是简单地使用文件中的证书,而不是:fullchain.pemcert.pem

ssl_certificate     /.../fullchain.pem;

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

于 2020-09-20T18:29:27.927 回答