使用 AndroidHttpClient 的 SSL/TLS 协议和密码套件

2023-11-21

编辑:如果我原来的帖子措辞不好,我深表歉意。这导致了一些混乱,表现为对原始帖子的评论。那么让我再试一次:

我从一个问题开始。我想解决 Android 上的问题,但不知道如何解决。我花了很多时间在网上寻找解决方案,但没有发现任何关于这个问题的讨论。尽管如此,包括 StackOverflow 线程在内的大量讨论让我发现了一种看起来很有前途的技术。我解决了这个问题。但解决方案有点复杂。所以我决定在这里发布这个问题,我想:a)一定有更好的解决方案,希望有人知道并在这里发布答案;或者b)也许这是一个很好的解决方案,并且由于我在网上其他任何地方都没有发现有关此事的讨论,也许我对问题的解决方案对于尝试做同样事情的其他人来说是有用的。无论哪种方式,结果都将是对 StackOverflow 的新贡献:一个在其他地方没有答案的问题,最终以某种方式得到正确的答案。事实上,当我最初发布问题时,StackOverflow 甚至邀请我通过分享我的知识来回答我自己的问题。事实上,这是我动机的一部分。就连我发现的任何地方都没有收集到这件事的事实。

So:

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

这个很重要。很好理解的一点是,服务器上可以做很多事情,但也有限制。同一台服务器必须为浏览器(包括旧浏览器)以及其他客户端提供服务。这意味着服务器必须支持广泛的协议和密码。即使在 Android 中,如果您必须支持许多不同的版本,您也必须支持许多不同的协议和密码。

更重要的是,默认情况下,OpenSSL 尊重客户端的密码首选项,not服务器的,在 SSL 握手期间。看到这个post例如,它表示您可以通过设置 SSL_OP_CIPHER_SERVER_PREFERENCE 来覆盖客户端中的该行为。目前还不完全清楚是否可以在 Java 中的 SSLSocket 上设置此选项。即使可以,您也可以自己设置密码列表或告诉您的客户端遵守服务器的列表。否则,您将获得 Android 默认值,无论您正在运行的版本是什么(而不是您链接的版本)。

如果采用默认值,可以看到 Jellybean 4.2+ 客户端从客户端发送到服务器的首选项列表here,从第 504 行左右开始。默认协议列表从第 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 中的 newInstance 方法(大约第 105 行)。

要点:

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

Then:

// 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 中repo.

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


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

我不相信你能做到AndroidHttpClient。我为强化通道所做的一切(例如密码列表、证书固定和公钥固定)都需要在某个地方有一个自定义类,无论是SSLSocketFactory or X509TrustManager。那是Java,那是Android。看使用 HttpsURLConnection 时如何覆盖 Android 发送到服务器的密码列表?.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 AndroidHttpClient 的 SSL/TLS 协议和密码套件 的相关文章

随机推荐

  • 如何保护我的进程不被杀死?

    我们在 Linux 之上有一个关键任务服务器程序 我们不希望其他人意外终止它 如果有人终止它或它崩溃 我们希望它重新启动 所以我们计划编写另一个程序 比如说程序B 我们希望程序B和服务器程序能够互相保护 如果我们的服务器程序退出 程序B将重
  • 在 Go 中向特定客户端发送 Websocket 消息(使用 Gorilla)

    我对 Go 很陌生 并且发现自己使用套接字作为我的第一个项目 这是一个多余的问题 但我无法理解如何 将 websocket 更新发送到 Go 中的特定客户端 使用 Gorilla 我试图解决的主要问题是 使用 websockets 和 ES
  • 停止 Jenkins 工作以防新工作开始

    是否可以指定 如果作业 A 被触发多次 则先前的作业将从队列中删除 并且只有最新的作业留在队列中或在有足够的空闲槽位时启动 提前致谢 use execute system groovy script step import hudson m
  • Python 通过写入 stdin 取消 raw_input/input?

    首先 我使用的是 python 2 7 5 和 Windows x64 我的应用程序针对的是这些参数 我需要一种方法来在一段时间过去后取消 raw input 目前 我的主线程启动两个子线程 一个是计时器 threading Timer 另
  • PyCharm 中的“未指定可执行文件”错误

    当我尝试在 PyCharm 中运行 python 脚本时 收到以下错误消息 error running myscript Executable is not specified 并且脚本不运行 如何通过 PyCharm 运行我的脚本 您需要
  • 如何将 PIL 图像对象上传到 Discord 聊天而不保存图像?

    我正在尝试将 PIL 图像对象发送到不和谐聊天 但我不想保存文件 我有一个函数可以从互联网收集图像 将它们垂直连接在一起 然后返回一个 PIL Image 对象 下面的代码从我本地计算机上的 PIL Image 对象创建一个文件图像 然后将
  • 使用 AWS API Gateway 请求验证器时启用 CORS

    我成功地使用 CORS 设置了 AWS API Gateway 当请求有效时 我有一个 200 状态代码和 CORS 标头 这很好 但是 当 AWS API Gateway 请求验证器检测到无效输入时 状态代码为 400 但未发送 CORS
  • Spring Data Rest 将自定义端点添加到特定存储库

    我想将自定义搜索端点添加到我现有的用户存储库 我的用户存储库如下所示 RepositoryRestResource collectionResourceRel users path users public interface UserRe
  • 在 Patchwork 中手动定位图例

    我想将图例 所有绘图共有 放置在拼凑布局的空白区域中 从我在网上可以找到的内容来看 我无法使用手动定位图例legend position如果我也使用guides collect 但可以使用左 右等 我尝试过使用l lt get legend
  • 如何查询内存中的一个DataTable来填充另一个数据表

    我正在尝试更新 Microsoft 报告 它的作用是写出有多少客户被排除在转换过程之外以及原因 目前 该程序将所有已删除的客户端写回到服务器 然后查询它以将结果填充到特殊表中 这是当前的查询 SELECT DeletedClients Re
  • 不同级别logback不同文件

    我的 logback xml 中有这个附加程序
  • 为什么我收到错误无法等待“void”?

    private Queue
  • 一个或多个实体的验证失败。有关更多详细信息,请参阅“EntityValidationErrors”属性[重复]

    这个问题在这里已经有答案了 我在使用代码优先方法为数据库播种时遇到此错误 一个或多个实体的验证失败 有关更多详细信息 请参阅 EntityValidationErrors 属性 说实话我不知道如何检查验证错误的内容 Visual Studi
  • 双向多对多关系中的循环引用

    我的实体中存在双向多对多关系 请参阅下面的示例 public class Collaboration JsonManagedReference COLLABORATION TAG private Set
  • Meteor 通过邮件查询其他用户

    我正在尝试使用以下命令通过电子邮件查询用户Meteor users findOne emails address email protected 它在 mongo shell 中工作 但在 Meteor 中返回未定义 有任何想法吗 UPDA
  • 固定元素在 Chrome 中消失

    当在我构建的网站上滚动时 使用 CSS 属性position fixed按预期工作 将导航栏保留在页面的最顶部 然而 在 Chrome 中 如果您使用导航栏中的链接 有时消失 通常 您单击的项目仍然可见 但并非总是如此 有时整个事情都会消失
  • AVPlayer 顶部绘制按钮

    我必须在视频顶部绘制标签或按钮relay next previous leave comment 视频列表有它 一旦用户从表中选择一项 就需要播放 播放器播放完成后 这些按钮或标签应该出现在视频顶部 这是我的代码 comPlayerCont
  • 在 LINQ 查询中使用 DateTime?.Value.TimeOfDay

    我正在尝试在 ASP NET MVC 3 上使用 LINQ 进行查询 我有一个模型 我们称之为事件 此 Event 对象有一个 Date 属性 即 DateTime 我想要的是获取 2 个时间跨度之间的事件 现在我的代码如下所示 TimeS
  • 对 3 个具有关系的实体进行建模

    假设我们的环境中有三个实体 Teacher Student and Course 每位教师拥有 教授 1 门或以上课程 且每门课程由 0 名或以上教师提供 每个学生已选修 1 门或多门课程 每门课程由 0 名或更多学生选修 每个教师有 0
  • 使用 AndroidHttpClient 的 SSL/TLS 协议和密码套件

    编辑 如果我原来的帖子措辞不好 我深表歉意 这导致了一些混乱 表现为对原始帖子的评论 那么让我再试一次 我从一个问题开始 我想解决 Android 上的问题 但不知道如何解决 我花了很多时间在网上寻找解决方案 但没有发现任何关于这个问题的讨