通过证书固定从您的android客户端与服务器进行安全通信_weixin_26747751的博客-程序员宅基地

技术标签: java  android  http  https  ssl  

Security and privacy are some of the most difficult tasks for any Android developer and it’s obvious because Android is an open-source platform and everyone knows how it works.

对于任何Android开发人员而言,安全性和隐私都是最艰巨的任务,这很明显,因为Android是一个开源平台,每个人都知道它的工作方式。

In this article, we’re going to deal with secure communication in Android, mainly between client and server.

在本文中,我们将处理Android中的安全通信,主要是客户端之间的通信 和服务器。

介绍 (Introduction)

Currently, the most common architecture of web services is REST-based on HTTP. The best protection method for this model of communication is the TLS/SSL standard.

当前,最常见的Web服务体系结构是基于HTTP的REST。 这种通信模型的最佳保护方法是TLS / SSL标准。

It can be combined with the HTTP protocol to create an encrypted variant called HTTPS. HTTPS ensures safe, encrypted communication between apps and server.

可以将其与HTTP协议结合以创建称为HTTPS的加密变体。 HTTPS确保应用程序和服务器之间的安全加密通信。

问题 (Problem)

It’s common for developers to implement networking calls over HTTPS, but not properly.

对于开发人员来说,通过HTTPS实施网络调用是很常见的做法,但是这样做不正确。

This can be solved by replacing the protocol name from HTTP to HTTPS in the URL. This will provide security to a certain extent by enabling TLS/SSL encryption by default (only if the server supports it).

可以通过将协议名称从HTTP替换为URL中的HTTPS来解决。 通过默认启用TLS / SSL加密(仅在服务器支持的情况下),这将在一定程度上提供安全性。

However, this is not good enough to keep your data secure. Simply replacing the protocol enables the encryption, but the app will trust every certificate issued by the server.

但是,这不足以确保数据安全。 只需替换协议即可启用加密,但是应用程序将信任服务器颁发的每个证书。

This means that the hacker can create fake certificates. The certificates will then allow the hacker to intercept encrypted communication which is well-known as a man-in-the-middle attack.

这意味着黑客可以创建伪造的证书。 然后,证书将允许黑客拦截加密的通信,这被称为中间人攻击。

It is the main reason why you should spend more time and effort to implement an HTTPS configuration correctly.

这是您应该花费更多的时间和精力来正确实现HTTPS配置的主要原因。

(Solution)

To avoid this threat, we should implement certificate pinning.

为了避免这种威胁,我们应该实现证书固定。

To do this, we need a server certificate with a fingerprint. We will compare the remote server certificate with the fingerprint while making the connection.

为此,我们需要带有指纹的服务器证书。 建立连接时,我们将比较远程服务器证书和指纹。

If they are identical, then it is a secure connection, otherwise, you should not do any data transfer as the connection is compromised.

如果它们相同,则表明它是安全连接,否则,由于连接受到破坏,您不应进行任何数据传输。

There are three ways to implement certificate pinning in Android:

有以下三种方法可在Android中实现证书固定:

  1. Network security configuration.

    网络安全配置。
  2. TrustManager.

    TrustManager。
  3. OkHttp and certificate pinning.

    OkHttp和证书固定。

网络安全配置 (Network Security Configuration)

This is one of the easiest ways and the native way to do certificate pinning in Android.

这是在Android中进行证书固定的最简单的方法之一。

Unlike the other two methods, this configuration requires no coding but network security configuration has one flaw: it only supports Android N and above.

与其他两种方法不同,此配置不需要编码,但是网络安全配置有一个缺陷:它仅支持Android N及更高版本。

The network security configuration feature lets apps customize their network security settings in a safe, declarative configuration file without modifying app code. These settings can be configured for specific domains and a specific app.

网络安全配置功能使应用程序可以在安全的声明性配置文件中自定义其网络安全设置,而无需修改应用程序代码。 可以为特定域和特定应用程序配置这些设置。

Network security configuration uses an XML file which has to be created under the res\xml directory and we need to declare this XML file in the manifest as shown below:

网络安全配置使用必须在res\xml目录下创建的XML文件,我们需要在清单中声明此XML文件,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>
</manifest>

Now that we know how to create a network security file, it’s time to configure it.

现在我们知道了如何创建网络安全文件,是时候对其进行配置了。

Here, we have two main tags, <base-config> and <domain-config>.

在这里,我们有两个主要标签, <base-config><domain-config>

  • <base-config> is used to declare things or configurations that should be applied to the entire app, regardless of which domain holds the connection.

    <base-config>用于声明应应用于整个应用程序的事物或配置,而不管哪个域拥有连接。

  • On the other hand, <domain-config> is used to configure specific rules to only certain domains of your choice.

    另一方面, <domain-config>用于将特定规则配置为仅对您选择的某些域进行配置。

Have a look:

看一看:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config  cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
  
   <domain-config>
        <domain includeSubdomains="true">secure.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/crtf"/>
        </trust-anchors>
   </domain-config>
</network-security-config>

Here, we used the <base-config> tag to disable clear-text traffic which means only HTTPS service calls will happen throughout the app and also mentions to use system certificates for networking.

在这里,我们使用<base-config>标记来禁用明文流量,这意味着整个应用程序中只会发生HTTPS服务调用,还提到使用系统证书进行联网。

But, coming to <domain-config>, we’ve mentioned a specific domain and configured certain rules for it, like only use the certificate file in the res/raw directory to make a network connection with the “secure.example.com” domain.

但是,在<domain-config> ,我们提到了一个特定的域并为其配置了某些规则,例如仅使用res/raw目录中的证书文件与“ secure.example.com ”建立网络连接。域。

Now that we know how to make use of the certificate, it’s time we use certificate pinning. Here, we use the <pin-set> tag to configure a certificate with a particular pin as shown below.

现在我们知道了如何使用证书,是时候使用证书固定了。 在这里,我们使用<pin-set>标记配置具有特定引脚的证书,如下所示。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">sampleexample.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

信托管理人 (TrustManager)

This is one of the oldest methods to implement certificate pinning in Android.

这是在Android中实现证书固定的最古老的方法之一。

TrustManager is responsible for deciding if the app should allow credentials given by the peer or not. This technique is from the javax.net.ssl package and we used it here to implement certificate pinning.

TrustManager负责确定应用程序是否应允许对等方提供的凭据。 该技术来自javax.net.ssl包,我们在这里使用它来实现证书固定。

第1步 (Step 1)

Add your certificate file in the res/raw directory. It would be preferable if the certificate is in PEM or DER format without any comment lines in it.

将证书文件添加到res/raw目录中。 如果证书为PEM或DER格式,且其中没有任何注释行,则将是更可取的。

第2步 (Step 2)

Initialize the KeyStore with a certificate as shown below:

如下所示使用证书初始化密钥库:

val resource_stream = resources.openRawResource(R.raw.cert)
val key_store_type = KeyStore.getDefaultType()
val key_store = KeyStore.getInstance(key_store_type)


key_store.load(resource_stream, null)

第三步 (Step 3)

Now that we have the certificate instance it’s time to initialize TrustManager.

现在我们有了证书实例,是时候初始化TrustManager了。

val trust_manager_algorithm = TrustManagerFactory.getDefaultAlgorithm()
val trust_manager_factory = TrustManagerFactory.getInstance(trust_manager_algorithm)


trust_manager_factory.init(keyStore)

第4步 (Step 4)

Now that we have the certificate and trust manager instances, let’s complete the final step by creating the SSL context with TLS protocol and then create a secure SSL connection with the TrustManager.

现在我们有了证书和信任管理器实例,让我们通过使用TLS协议创建SSL上下文,然后与TrustManager创建安全的SSL连接来完成最后一步。

val ssl_context = SSLContext.getInstance("TLS")
ssl_context.init(null, trust_manager_factory.trustManagers, null)
val url = URL("http://www.secureexample.com/")
val url_connection = url.openConnection() as HttpsURLConnection
url_connection.sslSocketFactory = ssl_context.socketFactory

OkHttp和证书固定 (OkHttp and Certificate Pinning)

OkHttp is a very famous networking library from Square. Retrofit uses OkHttp for networking. The Okhttp team has made it very simple to implement certificate pinning.

OkHttp是来自Square的非常著名的网络库。 改造使用OkHttp进行联网。 Okhttp团队使实现证书固定变得非常简单。

First, we need to create a certificate pinner instance from the dedicated OkHttp CertificatePinner builder and then we add a domain and corresponding fingerprint to it.

首先,我们需要从专用的OkHttp CertificatePinner构建器创建证书固定器实例,然后向其添加域和相应的指纹。

Finally, add the builder to the OkHttp client. Have a look:

最后,将构建器添加到OkHttp客户端。 看一看:

val certificatePinner = CertificatePinner.Builder()
       .add(
               "www.secureexample.com",
               "sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y="
       ).build()


val okHttpClient = OkHttpClient.Builder()
       .certificatePinner(certificatePinner)
       .build()

We can also add multiple fingerprints to the builder. This will be helpful to add additional fingerprints if the present one is going to expire. We can also import the certificate files to the resources folder, as shown in the TrustManager case.

我们还可以向构建器添加多个指纹。 如果当前的指纹即将过期,这将有助于添加其他指纹。 我们也可以将证书文件导入到资源文件夹,如TrustManager案例所示。

Now, you need to manually write a class that will extract the fingerprint from the file. You can also use the Peer certificate extractor to extract fingerprints.

现在,您需要手动编写一个类,该类将从文件中提取指纹。 您还可以使用对等证书提取器提取指纹。

It’s definitely not recommended to mention the fingerprints statically in the code. Mention them in the Gradle file as a build-config field.

绝对不建议在代码中静态提及指纹。 在Gradle文件中将它们作为build-config字段提及。

证书简介 (Briefly About Certificates)

There are almost 138 certificate authorities that are accepted by the Android ecosystem and the count increases every day.

Android生态系统接受了将近138个证书颁发机构,并且这一数字每天都在增加。

You can add your self-signed, leaf, intermediate, or root certificate. Let me explain these certificates a bit more so that you’ll have a good idea of what they are.

您可以添加自签名证书,叶证书,中间证书或根证书。 让我进一步解释这些证书,以便您对它们的含义有所了解。

树叶证书 (Leaf Certificate)

By using a leaf certificate you are making it 100% sure that this is your certificate exactly, and you are establishing a secure connection.

通过使用叶证书,您可以100%确保这正是您的证书,并且您正在建立安全连接。

Leaf certificates have a very short expiry time so you need to push the update to your app to make sure of the connectivity. It’s highly recommended to use back-up keys.

叶子证书的有效时间非常短,因此您需要将更新推送到您的应用程序以确保连接性。 强烈建议使用备份密钥。

中级证书 (Intermediate Certificate)

By using an intermediate certificate you’re depending on the intermediate certificate authority.

通过使用中间证书,您将依赖于中间证书颁发机构。

This method has an advantage. As long as you stick to the same certificate provider, then any changes to your leaf certificates will work without having to update your app. Using an intermediate certificate is secure only when your provider is trustworthy.

该方法具有优势。 只要您坚持使用同一证书提供者,那么对叶子证书的任何更改都将起作用,而无需更新您的应用程序。 仅在您的提供商可信赖的情况下,使用中间证书才是安全的。

根证书 (Root Certificate)

By using the root certificate, you’re depending on all of the intermediate certificates approved by the root certificate authority. If any of the intermediate certificates are compromised then there are chances for your app to be cracked by hackers.

通过使用根证书,您将依赖于由根证书颁发机构批准的所有中间证书。 如果任何中间证书被盗用,那么您的应用就有可能被黑客破解。

结论 (Conclusion)

My suggestion of using OkHttp with certificate pinning is the best way to go.

我建议将OkHttp与证书固定一起使用是最好的方法。

Although many of us prefer native network security configurations, as I said, it only supports Android N and above devices. There will be no complete protection with the native methods, yet.

尽管我们许多人都喜欢本机网络安全配置,但正如我所说,它仅支持Android N及更高版本的设备。 本地方法还没有完全的保护。

Hopefully, in a year or two, the minimum android version will reach Android N and then we can use the native security configuration.

希望在一两年内,最低的android版本将达到Android N,然后我们可以使用本机安全配置。

Thank you for reading.

感谢您的阅读。

翻译自: https://medium.com/better-programming/secure-communication-with-the-server-from-your-android-client-with-certificate-pinning-5f53cea55972

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_26747751/article/details/108935316

智能推荐

新手程序员选Offer?这几个原则考虑一下_大前端修行的博客-程序员宅基地

面试是公司选择你,Offer 是你选择公司。程序员这个职业在初期,门槛比较低,快速掌握一门编程语言,在工作中能参与有挑战且持续的项目,加入有活力和学习氛围的团队,初级程序员很快就能成长为高级工程师。这也是很多老程序员的焦虑所在,一旦自己稍微松懈一点,没能及时迭代自己的能力模型,那行业内不断涌入的新人就可能对自己形成威胁,无论是技术水平,还是充沛的体力和精力,新人都充满竞争力,并且,企业需要付给...

根据数组对象某一元素的id,找到此元素在数组所在的位置(findIndex)_js查询对象在数组的位置_有蝉的博客-程序员宅基地

var listData = [ {id:"1234",name:"bob"}, {id:"2451",name:"mary"}, {id:"6666",name:"tom"}, {id:"5675",name:"jerry"}, {id:"8421",name:"ken"},]let index = listData.findIndex( item...

触摸事件(含手势)_于海明的博客-程序员宅基地

一、概述在APP的开发过程中,可能需要利用手势操作去实现一些功能或者效果。UIKit框架提供了检测常见手势的预定义手势识别器。 在手势开发上,最好尽可能使用预定义的手势识别器,因为它们的简单性减少了我们的的代码量。当然,我们也可以自定义一些特殊的手势,具体的可以查看官方文档学习:Creating a Custom Gesture Recognizer。iOS中的事件可以分为3大类型:触

Untiy-Resources 加载图片_unity resources加载图片_zebintang的博客-程序员宅基地

一开始以为 将图片导入Unity时, 将其 图片转为sprite 以为就可以直接 load为sprite了,可是 一直报null异常原来是 加载后Debug出来是这个类型因为 加载的时候 是Texture2D类型,而我硬生生将其 转为 sprite,难怪会报异常了,其实 用 Load方法的话,一般会Loade第一个,而不会load子物体(sprite),然后sprit...

Docker布署Django框架外贸网站实操(一安装配置DOCKER)_无证的攻城狮的博客-程序员宅基地

项目简介1、最近学习了Python,Python这么火确实是有原因的。比较容易上手,当然也得有基础知识才好上手。语法比较人性化,既面向过程也可以面向对象。最喜欢它的缩进!太英明了,大大减少数括号的工作~2、正好有个外贸网站的项目,就采用DJANGO框架写了一个,速度快!DJANGO建站的速度那是杠杠的。正好Paypal又有Python的SDK,虽然是2.7的。改吧改吧也就能用了,不过这里面坑比...

CSS Sprites:鱼翅还是三鹿?_叶ch楼喽的博客-程序员宅基地

原文链接无处不在的 CSS sptites - 为数不多的几个可以直接跳过”流行”这个过程,而可以马上并且牢牢地跻身于最佳 CSS 实践之中的几个技术之一。虽然它真正流行是在 A List Apart 解释并认可这个技术之后,但是早在 2003 年 7 月份,Peter Stanicek 就已经开始谈论它了。目前大多数的开发人员对这个技术都有相当地掌握,也有很多关于它的教程和文

随便推点

用jquery获取form表单值的方法总结_jq from.get_gogiqp_jyh的博客-程序员宅基地

用jquery获取form表单值的方法总结 用jquery获取form表单值的方法总结: jquery获取radio单选按钮的值 $("input[name='items']:checked").val(); jquery radio取值,checkbox取值,select取值,radio选中,checkbox选中,select选中,及其相关 获取一组radio被选中项的值 var item

AttributeError: module ‘tensorflow.contrib‘ has no attribute ‘l2_regularizer‘_attributeerror: module 'tensorflow.keras.layers' h_Wanderer001的博客-程序员宅基地

这种错误一般是tensorflow中的类或对象指定错误。第十一行第十一行在contrib.后加上layers.

JVM-class文件详解(官方直译)含脑图_公众号:义笔记的博客-程序员宅基地

获取脑图方式请看最下面!JVM类文件(Class文件)结构ClassFile {u4 magic;u2 minor_version;u2 major_version;u2 constant_pool_count;cp_info constant_pool[constant_pool_count-1];u2 access_flags;u2

org.dom4j.DocumentException: 2 字节的 UTF-8 序列的字节 2 无效。 Nested exception: 2 字节的 UTF-8 序列的字节 2 无效。异常解决办法_程序员小刘的博客-程序员宅基地

本人最近因为自身需求,开始接触了XML技术,利用dom4j做一个对XML读写操作的时候,给原XML添加一条数据时遇到了这个错误。下面分享一下自己解决的心路历程吧。这是xml文件的内容:            张三        20        男        杭州        001                李四

Unity3d游戏引擎Windy系列教程:创建基础几何体&参数控制_风之子iis的博客-程序员宅基地

大家好,我是windy,今天给大家带来一个教程。有哪位光是创建基础几何体不足成为一篇博文,太水了,所以我还要讲用检视面板调整其参数。为了不大量使用外部图片,所以我还是使用之前使用过的,我不做商业目的,如有冒犯我会撤回。unity为广大开发者提供了五六个基础集合体,平面、立方体、圆柱等等我记得不太清楚了因为平时不太多回去用到他们,而且unity自带的几何体都比较精细...

使用fastjson时出现'Content-Type' cannot contain wildcard type '*'报错_FenG·的博客-程序员宅基地

在springmvc配置文件里添加:&amp;lt;mvc:annotation-driven&amp;gt; &amp;lt;mvc:message-converters&amp;gt; &amp;lt;bean class=&quot;com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter&quot;&amp;gt; ...

推荐文章

热门文章

相关标签