使用 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.创建一个实现X509TrustManager
的HttpsTrustManager
类:
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 签名的,而是自签名的 服务器配置缺少中间 CAOfficial 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