介绍

#

我们偶尔会收到关于 Dart 和 Flutter 应用程序安全漏洞的错误报告,这些报告是由为其他类型应用程序(例如用 Java 或 C++ 编写的应用程序)构建的工具生成的。本文档提供了有关我们认为不正确的报告的信息,并解释了担忧的缘由。

常见担忧

#

共享对象应使用强化函数

#

共享对象不包含任何强化函数。强化函数提供缓冲区溢出检查,以防范 glibc 的常见不安全函数(如 strcpygets 等)。使用编译器选项 -D_FORTIFY_SOURCE=2 来强化函数。

当这指的是已编译的 Dart 代码(例如 Flutter 应用程序中的 libapp.so 文件)时,此建议是错误的,因为 Dart 代码不直接调用 libc 函数;所有 Dart 代码都通过 Dart 标准库进行处理。

(通常情况下,MobSF 在此处会产生误报,因为它会检查任何使用带有 _chk 后缀的函数,但由于 Dart 完全不使用这些函数,因此它既没有带后缀也没有不带后缀的调用,MobSF 因此将代码视为包含未强化调用。)

共享对象应使用 RELRO

#

libapp.so 二进制文件未找到 RELRO

Dart 完全不使用常规的函数过程链接表 (PLT) 或全局偏移表 (GOT) 机制,因此重定位只读 (RELRO) 技术对于 Dart 来说实际上并没有太大意义。

Dart 中相当于 GOT 的是池指针,与 GOT 不同,它位于随机位置,因此更难被利用。

原则上,在使用 Dart FFI 时可以创建易受攻击的代码,但只要 Dart FFI 使用的代码本身适当使用了 RELRO,那么正常使用 Dart FFI 也不会容易出现这些问题。

共享对象应使用栈金丝雀值

#

libapp.so 二进制文件未找到金丝雀

此共享对象未将栈金丝雀值添加到栈中。栈金丝雀用于检测和防止利用程序覆盖返回地址。使用选项 -fstack-protector-all 来启用栈金丝雀。

Dart 不生成栈金丝雀,因为与 C++ 不同,Dart 没有栈分配的数组(这是 C/C++ 中栈溢出的主要来源)。

编写纯 Dart 代码(不使用 dart:ffi)时,由于纯 Dart 代码是一种托管语言,其中不存在缓冲区溢出等问题,因此您已经拥有比任何 C++ 缓解措施都更强的隔离保证。

原则上,在使用 Dart FFI 时可以创建易受攻击的代码,但只要 Dart FFI 使用的代码本身适当使用了栈金丝雀值,那么正常使用 Dart FFI 也不会容易出现这些问题。

代码应避免使用 _sscanf_strlen_fopen API

#

二进制文件可能包含以下不安全 API:_sscanf_strlen_fopen

报告这些问题的工具往往过于简化其扫描;例如,它们会查找具有这些名称的自定义函数,并假定它们指的是标准库函数。Flutter 的许多第三方依赖项都有名称相似的函数,这些函数会触发这些检查。有些情况可能是有效的担忧,但由于误报数量巨大,无法从这些工具的输出中判断。

代码应使用 calloc(而不是 _malloc)进行内存分配

#

二进制文件可能使用 _malloc 函数而不是 calloc

内存分配是一个复杂的主题,需要在性能和抵御漏洞的能力之间做出权衡。仅仅使用 malloc 并不一定表明存在安全漏洞。虽然我们欢迎具体的报告(见下文),但对于应优先使用 calloc 的情况,在实践中,将所有 malloc 调用统一替换为 calloc 是不合适的。

iOS 二进制文件设置了 Runpath Search Path(@rpath

#

二进制文件设置了 Runpath Search Path(@rpath)。在某些情况下,攻击者可以滥用此功能来运行任意可执行文件以执行代码并提升权限。删除编译器选项 -rpath 以移除 @rpath

在构建应用程序时,Runpath Search Path 指的是链接器搜索以查找应用程序使用的动态库 (dylibs) 的路径。默认情况下,iOS 应用程序将其设置为 @executable_path/Frameworks,这意味着链接器应在应用程序包内相对于应用程序二进制文件的 Frameworks 目录中搜索 dylibs。Flutter.framework 引擎与其他嵌入式框架或 dylibs 一样,会被正确复制到此目录中。应用程序运行时,会加载库二进制文件。

Flutter 应用程序使用默认的 iOS 构建设置 (LD_RUNPATH_SEARCH_PATHS=@executable_path/Frameworks)。

涉及 @rpath 的漏洞不适用于移动环境,因为攻击者无法访问文件系统,也无法任意替换这些框架。即使攻击者能够某种方式将框架替换为恶意框架,应用程序也会因代码签名违规而在启动时崩溃。

CBC 与 PKCS5/PKCS7 填充漏洞

#

我们收到了关于某些 Flutter 包中存在“CBC 与 PKCS5/PKCS7 填充漏洞”的模糊报告。

据我们所知,这是由 ExoPlayer 中的 HLS 实现(com.google.android.exoplayer2.source.hls.Aes128DataSource 类)触发的。HLS 是 Apple 的流媒体格式,它定义了 DRM 所需的加密类型;这不是漏洞,因为 DRM 并不保护用户的计算机或数据,而仅仅是提供混淆以限制用户完全使用其软件和硬件的能力。

应用程序可读写外部存储

#

应用程序可读写外部存储。任何应用程序都可以读取写入外部存储的数据。

与来自任何不受信任源的数据一样,您在处理来自外部存储的数据时应执行输入验证。我们强烈建议您不要在动态加载之前将可执行文件或类文件存储在外部存储上。如果您的应用程序确实从外部存储检索可执行文件,则在动态加载之前应先对文件进行签名和加密验证。

我们收到报告称,一些漏洞扫描工具将图像选择器插件读写外部存储的能力视为一种威胁。

从本地存储读取图像是这些插件的用途;这不是漏洞。

应用程序使用 file.delete() 删除数据

#

当您使用 file.delete 删除文件时,文件系统表中只删除了对文件的引用。文件仍然存在于磁盘上,直到被其他数据覆盖,使其容易被恢复。

一些漏洞扫描工具将摄像头插件在记录设备摄像头数据后删除临时文件视为安全漏洞。因为视频是由用户录制的,并且存储在用户的硬件上,所以没有实际风险。

已弃用的担忧

#

本节包含在使用旧版本 Dart 和 Flutter 时可能看到的有效消息,但现在这些消息应该不再出现。如果您在旧版本 Dart 或 Flutter 中看到这些消息,请升级到最新的稳定版本。如果您在当前稳定版本中看到这些消息,请报告它们(请参阅本文档末尾的部分)。

栈应设置 NX 位

#

共享对象未设置 NX 位。NX 位通过将内存页面标记为不可执行来防止内存损坏漏洞的利用。使用选项 --noexecstack-z noexecstack 将栈标记为不可执行。

(MobSF 的消息具有误导性;它检查的是栈是否被标记为不可执行,而不是共享对象。)

在 Dart 和 Flutter 的早期版本中,ELF 生成器存在一个错误,它没有发出具有 ~X 权限的 gnustack 段,但现在此问题已修复。

报告真实担忧

#

虽然自动漏洞扫描工具会报告上述误报,但我们不能排除存在需要密切关注的实际问题。如果您发现了一个您认为确实存在的安全漏洞,我们非常感谢您能将其报告给我们。