繁体   English   中英

使用 Android Native、Android Studio 和 retrofit 在 local.network 中信任我自己的自签名证书

[英]Trust my own self-signed certificate in local network using Android Native, Android Studio and retrofit

我正在创建一个简单的 android 应用程序,它将在封闭的 local.network 中使用。 在此 local.network 中,flask 服务器正在运行,该服务器配置为通过 nginx 代理使用自签名证书。 服务器的后端应用程序使用自签名证书工作正常,我已经使用我的浏览器和 postman 验证了这一点。(显然,我必须明确要求浏览器信任我的证书)。

几天来,我一直试图在网上找到一些关于如何让我的 android 应用程序接受我的证书的明确答案,但我尝试过的所有事情都让我陷入了死胡同。 有时解决方案已被弃用,而其他时候对于这种微不足道的事情来说太复杂了。

http请求使用Retrofit发送; 据我了解,我必须以某种方式配置我的 retrofit 实例的 http 客户端以接受我的证书。

我已经设法使用接受任何证书的客户端,但这不是我想要的。 理想情况下,我的证书将添加到官方 CA 默认信任的“证书集”中,这样应用程序也可以向外部资源发送请求。

因此,鉴于后端应用程序正在运行,例如 192.168.1.10:443,我将如何处理 go?

注意:我已阅读此处给出的说明https://developer.android.com/training/articles/security-config.html#TrustingAdditionalCas并添加了

android.networkSecurityConfig="@xml.network_security_config"

到我的清单文件,但出现以下错误:

Hostname 192.168.1.10 not verified: certificate sha256/...../.....并继续列出证书的信息,如通用名称等。

Shlomi Katriel 的回答是我已经尝试过的,但它间接地引导我找到了解决方案。 请记住,我能够解决这个问题的唯一原因是因为我拥有服务器的 root 访问权限并且可以随心所欲地使用它。

这个答案基本上是解决整个问题的关键。 我将发布所有步骤以防其他人需要。

步骤 1创建您的自签名证书。 就我而言,我使用了 openssl 实用程序。 包含 -addext 标志非常重要。 这是直接取自我上面链接的答案的示例:

openssl req \
-newkey rsa:2048 \
-nodes \
-x509 \
-days 36500 -nodes \
-addext "subjectAltName = IP.1:1.2.3.4" \
-keyout /etc/ssl/private/nginx-selfsigned2.key \
-out /etc/ssl/certs/nginx-selfsigned2.crt

将 1.2.3.4 替换为您服务器本地的 ip。 这将在证书的 subjectAltName 属性中包括服务器的本地 ip。 否则,您将不断收到错误“主机名...未验证...”

在正在运行的 nginx 实例中使用证书是一个不同的主题,可以轻松完成并且网上有大量资源。

第 2 步打开 android studio 并在名为rawres下创建一个新的 android 资源目录(如果您还没有的话)。 在此目录中,复制上述命令生成的 .crt 文件的内容。

步骤3在名为xmlres下创建android资源目录。 在那里,创建一个新的 xml 文件,在我的例子中,我称之为network_security_config.xml 在那里,我插入了以下内容:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="@raw/certificate"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

使用您在第 2 步中复制的证书文件的文件名,而不是“证书”。

第 4 步android.networkSecurityConfig="@xml.network_security_config"添加到 AndroidManifest.xml 中的应用程序元素

最佳解决方案

拉动字符串以使服务器所有者使用由自定义根 CA 签名的证书,然后使用networkSecurityConfig固定此证书。 在我看来,这应该是一项阻止功能发布的要求。

选择

我会创建 2 个 http 客户端:

  1. 一个接受所有证书( chechServerTrusted(...)的空 imolementation)的信任管理器被破坏 - 仅针对预期失败 SSL 握手的特定 local.network 请求。
  2. 正常一为 rest 的请求。

通过这样做,如果攻击者进入 local.network,您将公开此中间人攻击请求 - 攻击者和真实服务器证书均不受信任。 它们还可以模仿证书元数据,因此您不会区分它们。 只有您知道您的系统是否能够承受风险(以及风险的可能性有多大)。

更多见解:

  • networkSecurityConfig适用于众所周知的证书,因此您可以对公钥进行硬编码,所以我不相信它可以解决您的问题。
  • 如果没有实际的自签名证书,则无法在设备上安装证书颁发机构。

更新

根据Android Developers ,你需要如下配置:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="@raw/my_custom_cas"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

他们声称res/raw/my_custom_cas接受所有常见格式:

将 PEM 或 DER 格式的可信 CA 添加到res/raw/trusted_roots 请注意,如果使用 PEM 格式,该文件必须仅包含 PEM 数据而不能包含额外的文本。 您还可以提供多个<certificates>元素而不是一个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM