Android 通过 HTTPS 和 SSL 确保安全

Posted wecloud1314

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 通过 HTTPS 和 SSL 确保安全相关的知识,希望对你有一定的参考价值。

安全套接字层 (SSL)(现在技术上称为传输层安全协议 (TLS))是一个通用构建块,用于在客户端与服务器之间进行加密通信。应用很可能以错误的方式使用 SSL,从而导致恶意实体能够拦截网络上的应用数据。为了帮助您确保您的应用不会出现这种情况,本文重点介绍了使用安全网络协议的常见陷阱,并解决对使用公钥基础结构 (PKI) 关注较多的问题。

1、概念

在典型的 SSL 使用场景中,会使用一个包含公钥及与其匹配的私钥的证书配置服务器。作为 SSL 客户端与服务器握手的一部分,服务器将通过使用公钥加密签署其证书来证明自己具有私钥。

不过,任何人都可以生成他们自己的证书和私钥,因此,一个简单的握手只能说明服务器知道与证书公钥匹配的私钥,除此之外什么都证明不了。解决此问题的一个方法是让客户端拥有其信任的一个或多个证书集。如果证书不在此集合中,则不会信任服务器。

 

但这个简单的方法有几个缺点。服务器应能够随时间的推移升级到更强的密钥(“密钥旋转”),使用新的公钥替换证书中的公钥。遗憾的是,客户端应用现在必须根据服务器配置发生的变化进行更新。如果服务器不在应用开发者的控制下(例如,如果服务器是一个第三方网络服务),则很容易出现问题。如果应用必须与网络浏览器或电子邮件应用等任意服务器通信,那么,此方法也会带来问题。

为弥补这些缺点,通常使用来自知名颁发者(称为证书颁发机构 (CA))发放的证书配置服务器。主机平台一般包含其信任的知名 CA 的列表。从 android 4.2 (Jelly Bean) 开始,Android 目前包含在每个版本中更新的 100 多个 CA。CA 具有一个证书和一个私钥,这点与服务器相似。为服务器发放证书时,CA 使用其私钥签署服务器证书。然后,客户端可以验证该服务器是否具有平台已知的 CA 发放的证书。

不过,在解决一些问题的同时,使用 CA 也会引发其他问题。因为 CA 为许多服务器发放证书,因此,您仍需要某种方式来确保您与您需要的服务器通信。ssl证书申请

您会看到证书是由 RapidSSL CA 为与 *.wikipedia.org 匹配的服务器发放的。

2、一个 HTTPS 示例

假设您有一个由知名 CA 发放证书的网络服务器,那么,您可以使用如下简单代码发起安全的请求:

没错,就这么简单。如果您要调整 HTTP 请求,您可以切换到 HttpURLConnection。有关 HttpURLConnection的 Android 文档就如何处理请求和响应标头,以及如何发布内容、管理 Cookie、使用代理、缓存响应等提供了更多示例。但对于验证证书和主机名的细节,Android 框架在 API 中为您考虑了这些细节。这些是您尽可能想要实现的目标。不过,下面还有一些其他注意事项。

3、验证服务器证书的常见问题

假设没有从 getInputStream()接收内容,将引发异常:

出现此情况的原因有很多,其中包括:

颁发服务器证书的 CA 未知

服务器证书不是由 CA 签署的,而是自签署

服务器配置缺少中间 CA

下面几部分将讨论如何解决这些问题,同时保持与服务器的连接处于安全状态。

4、未知的证书颁发机构

在这种情况下,由于您具有系统不信任的 CA,将发生 SSLHandshakeException。原因可能是您有一个来自 Android 还未信任的新 CA 的证书,或您的应用在没有 CA 的较旧版本上运行。CA 未知的原因通常是因为它不是公共 CA,而是政府、公司或教育机构等组织发放的仅供自己使用的私有 CA。

幸运的是,您可以指示 HttpsURLConnection信任特定的 CA 集。此过程可能有点复杂,下面的示例展示了这个过程,从 InputStream获取一个特定的 CA,用该 CA 创建 KeyStore,然后用后者创建和初始化 TrustManager。TrustManager是系统用于从服务器验证证书的工具,可以使用一个或多个 CA 从 KeyStore创建,而创建的 TrustManager将仅信任这些 CA。

如果是新的 TrustManager,此示例将初始化一个新的 SSLContext,后者可以提供一个 SSLSocketFactory,您可以通过 HttpsURLConnection用它来替换默认的 SSLSocketFactory。这样一来,连接将使用您的 CA 验证证书。

5、自签署的服务器证书

导致出现 SSLHandshakeException的第二种情况是自签署证书,表示服务器将按照自己的 CA 进行操作。这与证书颁发机构未知的情况相似,因此,您可以使用前面部分介绍的方法。
您可以创建自己的 TrustManager,这次直接信任服务器证书。这种方法具有前面所述的将应用与证书直接关联的所有弊端,但可以安全地操作。不过,您应谨慎为之,以确保您的自签署证书具有合理的强密钥。从 2012 年开始,可以接受一个指数为 65537 的 2048 位 RSA 签名,此签名的有效期为一年。旋转密钥时,您应查看颁发机构(例如 NIST)针对可接受的密钥提供的建议。

6、缺少中间证书颁发机构

导致出现 SSLHandshakeException的第三种情况是缺少中间 CA。大多数公共 CA 不直接签署服务器证书。相反,它们使用自己的主要 CA 证书(称为根 CA)签署中间 CA。这样一来,根 CA 可以离线存储,从而降低泄露风险。不过,Android 等操作系统通常仅直接信任根 CA,这会在服务器证书(由中间 CA 签署)与证书验证程序(了解根 CA)之间留下一个小的信任缺口。为了解决这个问题,服务器在 SSL 握手期间不会仅向客户端发送它的证书,而是发送一个证书链,包括服务器 CA 以及到达可信的根 CA 所需要的任意中间证书。

有趣的是,在大多数桌面浏览器中访问此服务器不会引发完全未知的 CA 或自签署服务器证书所引发的类似错误。这是因为大多数桌面浏览器都会将可信的中间 CA 缓存一段时间。当浏览器从某个网站访问和了解中间 CA 后,下次它就不需要将中间 CA 添加在证书链中。

有些网站会专门为提供资源的辅助网络服务器这样做。例如,他们可能让具有完整证书链的服务器提供主 html 页面,让不包含 CA 的服务器提供图像、CSS 或 javascript 等资源,以节省带宽。遗憾的是,这些服务器有时候可能会提供您正在尝试从 Android 应用调用的网络服务,这一点让人难以接受。

可以通过两种方法解决此问题:

配置服务器以便在服务器链中添加中间 CA。大多数 CA 都可以提供有关如何为所有常用网络服务器执行此操作的文档。如果您需要网站至少通过 Android 4.2 使用默认 Android 浏览器,那么这是唯一的方法。

或者,像对待其他任何未知 CA 一样对待中间 CA,并创建一个 TrustManager以直接信任它,如前面的两部分中所述。

7、主机名验证的常见问题

正如本文开头所述,验证 SSL 连接有两个关键环节。首先是验证证书是否来自值得信任的来源,这是前面部分重点讲述的内容。而此部分侧重于第二个环节:确保您正在通信的服务器提供正确的证书。

出现此错误的一个原因是服务器配置错误。配置服务器所使用的证书不具有与您尝试连接的服务器匹配的主题或主题备用名称字段。许多不同的服务器可能使用一个证书。

不幸的是,还有另外一个原因也会引发此错误,即虚拟托管。当多个使用 HTTP 的主机名共享服务器时,网络服务器可以通过 HTTP/1.1 请求识别客户端正在寻找哪个目标主机名。遗憾的是,使用 HTTPS 会使情况变得复杂,因为服务器必须在看到 HTTP 请求前知道返回哪个证书。为了解决此问题,较新的 SSL 版本(特别是 TLSv.1.0 及更高版本)支持服务器名称指示 (SNI),后者允许 SSL 客户端向服务器指定预期的主机名,以便可以返回正确的证书。

幸运的是,自 Android 2.3 开始,HttpsURLConnection就支持 SNI。如果您需要支持 Android 2.2(及更旧的版本),一种解决办法是在一个唯一端口上设置备用虚拟主机,以便了解要返回哪个服务器证书。

比较极端的替代方法是不使用服务器默认情况下返回的验证程序,而是将 HostnameVerifier替换为不使用您的虚拟机主机名的验证程序。

8、有关直接使用 SSLSocket 的警告

到目前为止,所举示例都是侧重于使用 HttpsURLConnection的 HTTPS。有时候应用需要单独使用 SSL与 HTTP。例如,某个电子邮件应用可能使用 SSL 的变体 SMTP、POP3 或 IMAP。在这些情况下,应用将需要直接使用 SSLSocket,与 HttpsURLConnection在内部执行的操作非常相似。

目前为止所介绍的用于处理证书验证问题的技术也适用于 [SSLSocket]。事实上,使用自定义 TrustManager时,传递到 HttpsURLConnection 的是 SSLSocketFactory。因此,如果您需要使用一个带有 SSLSocket的自定义 TrustManager,请遵循相同的步骤,并使用 SSLSocketFactory创建您的 SSLSocket。

注意:SSLSocket不会执行主机名验证。由您的应用执行自己的主机名验证,最好通过使用预期的主机名调用 getDefaultHostnameVerifier()进行验证。另外,请注意,出现错误时,HostnameVerifier.verify不会引发异常,而是返回一个布尔结果,您必须明确地检查该结果。

列入黑名单

为了仅向正确验证的服务器和域的所有者发放证书,SSL 非常依赖 CA。少数情况下,CA 也会受骗,如 Comodo 和 DigiNotar 出现了信息泄露,从而导致某个主机名的证书被发放给服务器或域的所有者以外的其他人。

为了降低此风险,Android 提供了将某些证书甚至整个 CA 列入黑名单的功能。尽管此名单过去已内置到操作系统中,但从 Android 4.2 开始,可以远程更新此名单,便于处理将来的泄露问题。

证书固定

通过名称为证书固定的技术,应用可以更好地保护自己免受以欺诈方式发放的证书的攻击。这里基本上使用上面未知 CA 案例中提供的示例,将应用的可信 CA 限制在一个很小的 CA 集范围内,应用的服务器将使用这个集合。这样可以防止因泄露系统中其他 100 多个 CA 中的某个 CA 而破坏应用安全通道。

客户端证书

本文重点讲述 SSL 用户与服务器进行安全通信。SSL 也支持客户端证书的概念,客户端证书允许服务器验证客户端的身份。尽管这超出了本文的讨论范围,但使用的技术与指定自定义 TrustManager相似。请在 HttpsURLConnection的相关文档中查看有关创建自定义 KeyManager 的讨论。

Nogotofail:网络流量安全测试工具

对于已知的 TLS/SSL 漏洞和错配置,可以通过 Nogotofail 轻松确认您的应用程序是否安全。它是一款自动执行的工具,功能强大并且可扩展,用于测试通过它传送网络流量的任意设备的网络安全问题。

Nogotofail 可用于三个主要用例:

1、查找错误和漏洞。

2、验证修复并监测回归。

3、了解哪些应用和设备正在生成哪些流量。

以上是关于Android 通过 HTTPS 和 SSL 确保安全的主要内容,如果未能解决你的问题,请参考以下文章

转载 : Android webview在https下实现ssl的双向认证

转载 : Android webview在https下实现ssl的双向认证

(chap7 确保WEB安全的HTTPS) HTTPS通信步骤

(chap7 确保WEB安全的HTTPS) HTTPS和SSL

使用HTTPS与SSL来保证安全性

使用HTTPS与SSL来保证安全性