当前位置: 首页 > 面试题库 >

带有AndroidHttpClient的SSL / TLS协议和密码套件

顾英发
2023-03-14
问题内容

问:当使用AndroidHttpClient通过HTTPS发出REST请求时,如何指定要使用的SSL协议和密码?

这个很重要。众所周知,在服务器上可以做很多事情,但是有很多限制。同一台服务器必须为包括旧浏览器在内的浏览器以及其他客户端提供服务。这意味着服务器必须支持各种协议和密码。即使在Android中,如果您必须支持许多不同的版本,则也将必须支持许多不同的协议和密码。

更重要的是,默认情况下,在SSL握手期间,OpenSSL会遵守客户端的密码优先级, 而不是
服务器的密码优先级。例如,请参阅此文章,该文章说您可以通过设置SSL_OP_CIPHER_SERVER_PREFERENCE在客户端中覆盖该行为。尚不清楚是否可以在Java中的SSLSocket上设置此选项。即使可以,您也可以自己设置密码列表,也可以告诉客户端遵守服务器列表。否则,您将获得Android默认值,无论运行的版本是什么(而不是链接所针对的版本)。

如果采用默认值,则可以在此处从504行开始看到客户端发送的Jellybean
4.2+客户端的首选项列表。协议的默认列表从620行开始。尽管Jellybean
4.2+包括对OpenSSL的支持1.0.1,尤其是TLSv1.1和TLSv1.2,默认情况下未启用这些协议。如果您不做我做过的事情,则无法利用TLSv1.2支持,尽管事实上在最新版本的Android上宣传了对TLSv1.2的支持。当您返回以前的Android版本时,细节会有很大不同。至少,您可能希望仔细查看所有受支持版本的默认值,并查看客户端的实际操作。您可能会感到惊讶。

关于支持各种协议和密码,您可以说更多的话。关键是,有时可能需要在客户端中更改这些设置。

A.使用自定义SSLSocketFactory

这对我来说效果很好,最后,它并不是很多代码。但是由于以下几个原因,它有点棘手:

  • 有两个不同的SSLSocketFactory类。客户端需要一个org.apache.http.conn.ssl.SSLSocketFactory,但是OpenSSL返回一个javax.net.ssl.SSLSocketFactory。这绝对是令人困惑的。我使用委派使一个呼叫另一个,没有太大问题。
  • 请注意OpenSSLContextImpl和SSLContextImpl之间的区别。一个只包装另一个,但不能互换。当我使用SSLContextImpl.engineGetSocketFactory方法时,我忘记了到底发生了什么,但是却悄无声息地失败了。确保使用OpenSSLContextImpl而不是SSLContextImpl来获取套接字工厂。您也许还可以使用javax.net.ssl.SSLSocketFactory.getDefault(),但我不确定。
  • 您不能轻易地继承AndroidHttpClient的子类,因为它的构造函数是私有的。这很不幸,因为它还提供了其他一些好处,例如确保您将其正确关闭而不浪费资源。DefaultHttpClient正常工作。我从AndroidHttpClient(约105行)处借用了newInstance方法。

重点:

public class SecureSocketFactory extends SSLSocketFactory {
    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        // order should not matter here; the server should select the highest
        // one from this list that it supports
        s.setEnabledProtocols(new String[] { "TLSv1.2", "TLSv1" });

        // order matters here; specify in preference order
        s.setEnabledCipherSuites(new String[] { "ECDHE-RSA-RC4-SHA", "RC4-SHA" });

然后:

// when creating client
HttpParams params;
SchemeRegistry schemeRegistry = new SchemeRegistry();

// use custom socket factory for https
SSLSocketFactory sf = new SecureSocketFactory();
schemeRegistry.register(new Scheme("https", sf, 443));

// use the default for http
schemeRegistry.register(new Scheme("http",
            PlainSocketFactory.getSocketFactory(), 80));

ClientConnectionManager manager =
            new ThreadSafeClientConnManager(params, schemeRegistry);

HttpClient client = new DefaultHttpClient(manager, params);

在Android 3.0(Honeycomb / SDK 11)以下版本中,受支持的密码选择变得更加有限,并且没有太多动机来覆盖默认设置。在FROYO /
SDK 8上,由于某种原因,我的SecureSocketFactory炸毁了,评审团在10名上脱颖而出。但是对于11点以上的工作似乎还不错。

完整的解决方案在公共github
仓库中。

另一个解决方案可能是使用HttpsUrlConnection,这使使用自定义套接字工厂变得容易,但是我想您可能会失去高级HTTP客户端的更多便利。我对HttpsUrlConnection没有任何经验。


问题答案:

使用AndroidHttpClient通过HTTPS发出REST请求时,如何指定要使用的SSL协议和密码?

我不相信您可以做到AndroidHttpClient。我为加强通道所做的所有工作(例如密码列表,证书固定和公钥固定)都需要在某个地方自定义类,无论它是SSLSocketFactory还是X509TrustManager。那是Java,那是Android。请参阅使用HttpsURLConnection时如何覆盖由Android发送到服务器的密码列表?。



 类似资料:
  • 根据下面的代码,如何将协议设置为TLSv1.2、TLSv1、SSLv3? 使用SoapUi,我可以使用以下配置请求服务:-dSOAPUI.https.protocols=TLSv1.2,TLSv1,SSLv3 使用CXF,我得到一个“javax.net.ssl.SSLHandShakeException:没有适当的协议(协议被禁用或密码套件不适当)” 很抱歉我对Soap和SSL的知识很差...

  • TLS名为传输层安全协议(Transport Layer Security Protocol),这个协议是一套加密的通信协议。它的前身是SSL协议(安全套接层协议,Secure Sockets Layer)。这两个协议的工作方式类似,但TLS协议针对SSL协议进行了一些改善。SSL/TLS协议利用加密的方式,在开放的互联网环境中实现了加密通信,让通信的双方可以安心的说悄悄话。。 加密 SSL协议的

  • 我试图使用PowerShell从https网站抓取html内容。 不幸的是,该站点只例外一组有限的SSL/TLS密码套件,不支持Powershell可用的套件。 如果尝试使用Invoke-WebRequest cmdlet,我会收到以下错误消息: 调用-网络请求:请求被中止:无法创建SSL/TLS安全通道。 问题: 是否有办法指定PowerShell使用的客户端SSL/TLS密码套件? 还有其他c

  • 反之亦然,如何找出哪些密码套件可用于特定版本的SSL/TLS协议?这两个问题都意味着存在限制,即任何密码套件都不适用于任何协议版本。特别是,我想在TLS 1.2适用密码的详尽列表中指出,如果有的话。 这个问题可以重新表述为密码套件和协议版本之间的兼容性。

  • 我知道这个话题还有其他一些问题(有答案)。但这些对我都没有帮助。 我有一个postfix服务器(debian 10上的postfix 3.4.14),配置如下(只有有趣的部分): 好的,首先我删除了中的扩展,因为这没有帮助而且是错误的(感谢dave_thompson_085的提示)。 下面是发送电子邮件的Java代码(代码有一个“很长”的历史,所以请不要奇怪为什么使用,而不是...) 为了调试,我

  • 我曾尝试将java 11.0.9连接到MySQL 5.6连接器,但在服务器中出现以下错误,但在本地相同的代码中工作正常 引起:javax.net.ssl.SSLHandshakeException:没有适当的协议(协议被禁用或密码套件不合适)在java.base/sun.security.ssl.HandshakeContext.(未知源)在java.base/sun.security.ssl.C