Android 8:不允许明文HTTP流量

1686

我收到来自使用Android 8的用户的报告,称我的应用程序(使用后端提要)无法显示内容。经过调查,我发现在Android 8上发生以下异常:

08-29 12:03:11.246 11285-11285/ E/: [12:03:11.245, main]: Exception: IOException java.io.IOException: Cleartext HTTP traffic to * not permitted
at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:115)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:458)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.doConnection(AbstractHttpAsyncTask.java:207)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.extendedDoInBackground(AbstractHttpAsyncTask.java:102)
at com.deiw.android.generic.tasks.AbstractAsyncTask.doInBackground(AbstractAsyncTask.java:88)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

在 Android 7 及以下版本上,一切正常。我没有在 Manifest 中设置 android:usesCleartextTraffic(将其设置为 true 也没有帮助,因为默认值就是这个),也没有使用网络安全信息。如果我调用 NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(),它会返回 false(针对 Android 8),返回 true(针对旧版本),并且仍然使用同一个 apk 文件。 我试图在 Google 上寻找 Android O 相关的信息,但未获得成功。


6
由于服务器在某些情况下将HTTPS重定向到HTTP,导致我维护的应用程序出现了这种情况。 - Big McLargeHuge
请在此处查看:https://codechacha.com/android-cleartext-http-traffic-issue/ - ikmazameti
我正在构建API级别为30的Android 11应用程序,并在清单文件中的应用程序标记中添加android:usesCleartextTraffic="true"。 - masterxilo
据其他地方报道,直到Android 9才会发生这种情况。这对我来说是个新闻。 - undefined
37个回答

3319
根据《网络安全配置》,从 Android 9 (API 级别 28) 开始,默认情况下禁用明文支持。

也可以参考《Android M 和明文流量之战》

来自 Google 的代码实验室的解释

选项1 -

首先尝试使用https://而不是http://访问 URL。

选项2 -

创建文件 res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">api.example.com(to be adjusted)</domain>
    </domain-config>
</network-security-config>

AndroidManifest.xml -

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

选项 3 -

android:usesCleartextTraffic 文档

AndroidManifest.xml -

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>

正如@david.s'的回答所指出的,android:targetSandboxVersion也可能会成为问题 -

根据清单文档 -

android:targetSandboxVersion

此应用程序要使用的目标沙箱。沙箱版本号越高,安全级别就越高。其默认值为1; 您还可以将其设置为2。将此属性设置为2会将应用程序切换到另一个 SELinux 沙箱。以下限制适用于 2 级沙箱:

  • 网络安全配置中usesCleartextTraffic的默认值为false。
  • 不允许 UID 共享。

因此,选项4-

如果您在<manifest>中有android:targetSandboxVersion,请将其降低到1

AndroidManifest.xml -

<?xml version="1.0" encoding="utf-8"?>
<manifest android:targetSandboxVersion="1">
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

7
感谢你的答案,@HrishikeshKadam,但最近版本的P似乎还需要另一个步骤?请看我的问题:https://dev59.com/KVQK5IYBdhLWcg3wev6V - spartygw
8
ClearText HTTP表示他们只是使用普通的HTTP网站而非HTTPS。 - Tom Hammond
304
如果每个开发者都会添加android:usesCleartextTraffic="true",那么这个安卓安全功能还有什么意义? - 林果皞
98
这甚至没有提到解决这个问题的最佳方案:使用HTTPS。在这个答案中提到的选项应该只是最后的选择。 - Christian Brüggemann
11
谷歌应用商店最终可以轻松地禁止使用此标记的应用程序。 - Karan Harsh Wardhan
显示剩余24条评论

260

我在Android 9上的问题是在webview中导航到具有http的域 来自这个答案的解决方案。

<application 
    android:networkSecurityConfig="@xml/network_security_config"
    ...>

并且:

res/xml/network_security_config.xml

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

我能否用gradle重新编写这个? - Morozov
1
对我不起作用。我无法让模拟器连接到10.0.2.2。 - Gilbert
这在发布版本中并不是最“安全”的做法。 - Murciegalo84
如果我想把端口号放在一起怎么办? - Panadol Chong
对我来说工作得很好!谢谢! - Abdel Aleem

182
在AndroidManifest中,我发现了这个参数:
android:networkSecurityConfig="@xml/network_security_config"

同时在network_security_config.xml中定义了@xml/network_security_config:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!--Set application-wide security config using base-config tag.-->
    <base-config cleartextTrafficPermitted="false"/>
</network-security-config>  

我只是将cleartextTrafficPermitted更改为true。


2
完美。更多信息请参见:https://codelabs.developers.google.com/codelabs/android-network-security-config/index.html#3 - 1x2x3x4x
2
更改后请重新安装应用程序。 - Gilbert
唯一有效的答案是对我起作用的(我必须创建文件并添加参数)。 - Carlos López Marí
4
除非这是内部应用程序,否则禁用 SSL 要求不是一个好的做法。但即使是这样,也永远不应该被禁用。 - c-sharp-and-swiftui-devni

151

您可能只想在调试时允许明文传输,但保留拒绝明文传输的安全优势来进行生产。这对我很有用,因为我将我的应用程序与不支持HTTPS的开发服务器进行测试。以下是如何在生产中强制执行HTTPS,但在调试模式下允许明文传输:

在 build.gradle 文件中:

// Put this in your buildtypes debug section:
manifestPlaceholders = [usesCleartextTraffic:"true"]

// Put this in your buildtypes release section
manifestPlaceholders = [usesCleartextTraffic:"false"]
在AndroidManifest.xml文件的application标签中。
android:usesCleartextTraffic="${usesCleartextTraffic}"

1
这段代码只适用于API 23及以上版本。如果您想要一个API独立的解决方案,可以考虑使用以下链接中提供的经过验证的方法: https://dev59.com/h1YO5IYBdhLWcg3wIuPp - Rik van Velzen
1
问题:当应用程序使用可以通过设计为http或https的Web服务器时,如果http URL需要使用Web服务,usesCleartextTraffic:“false”是否有任何影响?因此,将其设置为true意味着默认情况下https服务不会发送明文吗? - whyoz

71

好的,这不是重复成千上万次地将其添加到您的清单中,而是一条基于此的提示,但可以为您提供额外的好处(也许还有一些背景信息)。


以下解决方案允许您针对每个环境设置协议(HTTP / HTTPS)。

这样,您可以在开发环境中使用 http,而在生产环境中使用 https,而无需一直更改它! 这是必需的,因为通常您没有本地或开发环境的 https 证书,但对于生产环境(也许是测试环境),它是必不可少的。


Android 具有用于 src 目录的一种覆盖功能。

默认情况下,您有

/app/src/main

但是您可以添加其他目录以覆盖 AndroidManifest.xml。以下是其工作原理:

  • 创建目录 /app/src/debug
  • 内部创建 AndroidManifest.xml

在此文件中,您不需要放置所有规则,而仅需放置您希望从您的 /app/src/main/AndroidManifest.xml 覆盖的规则。

以下是所请求的 CLEARTEXT 权限的示例:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.yourappname">

    <application
            android:usesCleartextTraffic="true"
            android:name=".MainApplication"
            android:label="@string/app_name"
            android:icon="@mipmap/ic_launcher"
            android:allowBackup="false"
            android:theme="@style/AppTheme">
    </application>

</manifest>

有了这些知识,你现在可以轻松地根据你的debug | main | release环境来 overload your Permissions

最大的好处是... 在你的产品清单中不会有debug-stuff,从而保持了一个直观易懂、易于维护的结构。


9
这绝对是正确的解决方案。Android 添加了这些安全设置是有原因的,所以它们应该保持不变。你的解决方案允许我们在本地不安全的环境中进行测试,而生产构建将仍然具有推荐的安全设置。谢谢! - Coo
在生产环境中,最后一步几乎总是明文的,无论如何。人们可能会认为在开发者模式下,我们可以通过切换来覆盖这一点。 - undefined

60
如果可能,请将您的URL从HTTP更改为HTTPS;这样做是可行的!!!

162
这怎么会被点赞了呢?如果你的服务器网址不是https,你将会收到一个握手异常。 - Karan Harsh Wardhan
27
因为做正确的事情(在生产环境中),所以给你点赞。 HTTPS 应该成为默认选项,而不是 HTTP。 - beetstra
54
你假设你完全掌控提供内容的方式。因此,这个答案显得天真或轻率。 - Martin Price
14
为什么在本地调试时,HTTPS应该是默认设置?这太愚蠢了,只是Google家长式作风的又一个例子。幸运的是,可以通过Tyler的解决方案来绕过调试模式中的此问题。 - Bevor
12
答案无视了问题本身。和小公司的人不同,有时你并没有为每个分段服务器配置SSL证书。这个答案就像是有人在Facebook帖子中纠正语法一样糟糕,并且完全没有回答问题,也没有解决问题。 - Nick Turner
显示剩余8条评论

54
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">***Your URL(ex: 127.0.0.1)***</domain>
    </domain-config>
</network-security-config>
在上面提供的建议中,我提供了我的URL:http://xyz.abc.com/mno/
我将其更改为xyz.abc.com,然后它开始工作了。

15
Domain(域名)不等于URL。"http"是协议,协议从未成为域名的一部分。 - The incredible Jan
这是正确的,只支持全限定域名(FQDN),不支持IP地址(已在上面修复)。 - Martin Zeitler
无法在域10.0.2.2上工作。我应该添加端口号吗? - Gilbert
如果我使用IP地址而不是域名怎么办? - Panadol Chong

35

这可能对某些人有用。

我们最近在Android 9上遇到了同样的问题,但我们只需要在WebView中显示一些Url,没有什么特别的。因此,在清单中添加android:usesCleartextTraffic="true"可以解决,但我们不想为此损害整个应用程序的安全性。 所以解决方法是将链接从http更改为https


4
如果我只想显示一些链接,我不需要使用 WebView,只需要使用 TextView。 ;) 我想你的意思是显示一些 HTML 页面。你的修复方法仅在服务器提供 SSL 的情况下才有效。你不能简单地更改链接。 - The incredible Jan
2
这肯定是最好的选择,但有时候我们不能选择它——可能是出于性能原因,或者仅仅因为资源在明文HTTP中不可用。 - Dakatine
我们不想危及整个应用程序的安全性。这可能会导致哪些安全风险?在我的情况下,没有一个URL,所以我无法将它们添加到清单中。 - Robert Williams
嗨@RobertWilliams,它只是意味着允许非加密流量的明文流量。这里有一篇博客文章https://medium.com/@son.rommer/fix-cleartext-traffic-error-in-android-9-pie-2f4e9e2235e6 - El_o.di

30

对于React Native项目

这个问题已经在RN 0.59版本中解决了。 您可以在从0.58.6升级到0.59的差异比较中找到相关信息。 您可以按照下面的步骤进行应用,而无需升级您的RN版本:

创建以下文件:

android/app/src/debug/res/xml/react_native_config.xml-

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="false">localhost</domain>
    <domain includeSubdomains="false">10.0.2.2</domain>
    <domain includeSubdomains="false">10.0.3.2</domain>
  </domain-config>
</network-security-config>

android/app/src/debug/AndroidManifest.xml -

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools">

  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

  <application tools:targetApi="28"
      tools:ignore="GoogleAppIndexingWarning" 
      android:networkSecurityConfig="@xml/react_native_config" />
</manifest>

查看被接受的答案以了解根本原因。


2
我使用的是react-native 0.59.5版本,并且遇到了相同的问题,我们需要按照您的建议手动设置AndroidManifest.xml文件。 - Cristian Mora
谢谢,它帮了我很多。由于 Google 政策的原因,我不得不设置 android:usesCleartextTraffic="false",然后我在模拟器中运行本地的 React Native 时遇到了问题。我按照上述步骤操作后,问题得到了解决。 - Hidayat Arghandabi

22

我已经从Android清单文件中删除了已经存在的这行代码。

 android:networkSecurityConfig="@xml/network_security_config" 

并且添加了

android:usesCleartextTraffic="true"

将此代码添加到清单文件中的应用程序标签中

<application
    android:usesCleartextTraffic="true"
    android:allowBackup="true"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    >

那么在安卓9和10中,这个错误“不允许使用明文HTTP流量到overlay.openstreetmap.nl” 就消失了。我希望这也适用于安卓8,如果这对你有所帮助,请不要忘记投票,谢谢。


救了我的命,非常感谢 ☺️ - Anshul Tyagi
这会不会影响应用程序的任何现有功能? - Anshul Tyagi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接