☰
iOS UIActivity 分享机制安全指南:Share Sheet 数据收发、排除限制与自定义 Activity 检测(OWASP MASTG)
2026/10/8 1:25:35 网站建设 项目流程
  • 文档
  • 教程
  • 网络安全

【免费下载链接】mastg

The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.

项目地址:https://gitcode.com/gh_mirrors/ow/mastg
点击查看免费下载

本文基于 OWASP Mobile Application Security Testing Guide(MASTG)知识库中的 MASTG-KNOW-0081 展开,面向 iOS 开发者与移动安全测试人员。文章系统讲解UIActivityViewController(Share Sheet)的初始化、内置 Activity 类型、excludedActivityTypes的真实安全边界、接收文件时的Info.plist声明与Documents/Inbox/处理规范,并结合 MASTG 配套的 MASTG-TECH-0167、MASTG-TECH-0168 等技术文章给出 Frida 动态插桩检测方案。读完本文,你将能准确判断"哪些分享行为是用户授权范畴、哪些是 App 可以通过 API 强制约束的",并能对任意 iOS App 的分享发送与接收链路进行源码级与运行时级安全验证。

上图展示了在 Safari 中分享一个链接时所呈现的典型 Share Sheet。自 iOS 6 起,App 可以通过系统级"分享面板"(Share Sheet)共享数据(items),其底层实现是UIActivityViewControllerAPI;对用户而言,这就是 iOS 中随处可见的"分享"按钮。

初始化一个 UIActivityViewController

开发者通过调用init(activityItems:applicationActivities:)创建UIActivityViewController,传入两个参数:

  • activityItems:一个待分享数据对象组成的数组。元素可以是任何符合UIActivityItemSource协议的类型,也可以是可直接分享的类型,例如String、URL、UIImage。
  • applicationActivities:一个可选的数组,由 App 自定义的UIActivity子类实例构成,用于表示 App 特有的服务。传nil表示不提供任何自定义 Activity。

下面是一个分享"字符串 + URL"的 Swift 示例:

let activityVC = UIActivityViewController( activityItems: ["Hello, World!", URL(string: "https://example.com")!], applicationActivities: nil ) present(activityVC, animated: true)

从安全测试的角度看,init(activityItems:applicationActivities:)的入参恰好暴露了三类最关键的信息:

  • 被分享的数据(activityItems,可能包含 URL、文本、图片等敏感内容);
  • App 自定义的服务(applicationActivities,即自定义 Activity 实例);
  • 被排除的分享目标(excludedActivityTypes,见下文)。

这正是 MASTG-TECH-0167(Monitoring UIActivity Data Sharing)用 Frida 挂钩该初始化方法的原因:运行时观察activityItems与applicationActivities,即可还原 App 到底"准备把什么数据、通过哪些渠道"分享出去。

系统内置的 Activity 类型

系统在UIActivity.ActivityType中定义了一套内置 Activity 类型,常见的有:

  • airDrop
  • assignToContact
  • copyToPasteboard
  • mail
  • message
  • saveToCameraRoll
  • addToReadingList
  • markupAsPDF
  • print

遗留社交类型已不再可用

一组遗留的社交分享类型——postToFacebook、postToTwitter、postToWeibo、postToVimeo、postToFlickr、postToTencentWeibo——在当代 iOS 上不应再被依赖。这些类型绑定的是旧的系统级 Social framework 与账户集成:

  • <Social/SLServiceTypes.h>中的相关服务常量已在 iOS 11 SDK 中标记废弃;
  • iOS 11 移除了设置(Settings)层面的社交账户集成能力。

因此,这些遗留的内置社交 Activity 在现代 iOS 上通常不会作为系统提供的分享目的地出现。如今的社交分享大多通过已安装 App 提供的分享扩展(share extension)暴露,而这些扩展使用自己的 Activity 类型,与旧的UIActivity.ActivityType.postTo...常量无关。

excludedActivityTypes:排除分享目标及其安全边界

App 可以在展示控制器之前设置excludedActivityTypes属性,以限制呈现的 Activity 类型:

activityVC.excludedActivityTypes = [ .saveToCameraRoll, .addToReadingList, .airDrop, ]

如果excludedActivityTypes未设置或为nil,则呈现所有可用的 Activity 类型。

重要限制:它不是安全边界

这个控制手段存在关键限制,不能被视为安全边界:

  • 只影响内置系统 Activity。正如 Apple 框架工程师所确认的,App"不允许排除来自其他 App 的扩展 Activity"——因此第三方分享扩展(例如第三方即时通讯软件、云存储 App)——恰恰是现代 iOS 上占主导地位的分享渠道——根本无法被排除。
  • 内置集合会随 iOS 版本增长。新引入的类型不会被自动排除,因此任何排除清单都不可能穷尽。

在实践中,excludedActivityTypes的合理用途是隐藏对某个特定 item 没有意义的分享目的地(例如对一份文本文档隐藏"存储到相机胶卷"),而不是保护敏感数据。当 App 呈现 Share Sheet 时,数据去向由用户主动决定,而最常见的分享目的地(第三方分享扩展)根本无法被 API 排除。因此,"某个 item 是否应该被分享"本质上是**用户授权(user-consent)**问题,而不是 App 能通过这个 API 在技术上强制执行的。

MASTG 对此的立场在 MASTG-TEST-0071(Testing UIActivity Sharing)的废弃说明中得到了明确重申:该测试"在设计上不存在 MASTG v2 的继任者",因为是否通过 Share Sheet 分享某个 item 是用户的授权决策,而excludedActivityTypes不是安全控制——它无法限制现代 iOS 上占主导地位的第三方分享扩展。其静态与动态分析技术分别被保留为 MASTG-TECH-0167 与 MASTG-TECH-0168。

接收分享数据:Info.plist 声明与 Inbox 处理

App 同样可能处于 Share Sheet 及跨 App 文件分享的接收端。当 App 声明它可以打开某些文件或文档类型时,其他 App(以及 AirDrop、Mail 等)就可以把文件交给它。相关声明都位于 App 的Info.plist中:

  • UTExportedTypeDeclarations/UTImportedTypeDeclarations:声明 App 导出或导入的自定义统一类型标识符(UTI,Uniform Type Identifiers)。
  • CFBundleDocumentTypes:声明 App 可以打开的文档类型。每个条目由一个名称和一个或多个表示数据类型的 UTI 组成(例如 PNG 文件对应public.png)。iOS 用该键判断 App 是否有资格打开某个文档——仅通过UTExportedTypeDeclarations/UTImportedTypeDeclarations声明 UTI 是不够的。

当其他 App 或系统把文件交给 App 时,iOS 通过以下回调交付:

  • application(_:open:options:):适用于使用传统 App Delegate 生命周期的 App;
  • scene(_:openURLContexts:):适用于使用 UIScene 生命周期的 App。

App 有责任校验收到的 URL 与文件,并在处理完成后删除被放置在其Documents/Inbox/目录中的任何文件。

实战:静态分析接收端声明

MASTG-TEST-0071 给出了一份真实文件管理器 App 的Info.plist分析示例。在没有源码的情况下,可以通过 objection(MASTG-TOOL-0038)直接读取:

objection --name SomeFileManager run ios plist cat Info.plist

该 App 未声明导入的自定义文档类型,但声明了导出类型:

UTExportedTypeDeclarations = ( { UTTypeConformsTo = ( "public.data" ); UTTypeDescription = "SomeFileManager Files"; UTTypeIdentifier = "com.some.filemanager.custom"; UTTypeTagSpecification = { "public.filename-extension" = ( ipa, deb, zip, rar, tar, gz, ... key, pem, p12, cer ); }; } );

同时,App 还通过CFBundleDocumentTypes声明了它可以打开的文档类型:

CFBundleDocumentTypes = ( { ... CFBundleTypeName = "SomeFileManager Files"; LSItemContentTypes = ( "public.content", "public.data", "public.archive", "public.item", "public.database", "public.calendar-event", ... ); } );

可见这个文件管理器会尝试打开任何符合LSItemContentTypes所列 UTI 的文件,并准备打开UTTypeTagSpecification/"public.filename-extension"所列扩展名的文件。测试人员应记下这些范围,因为在后续动态分析中,针对不同文件类型做畸形输入或模糊测试时,这些声明直接决定了攻击面。

实战:动态观察文件接收链路

MASTG-TECH-0168(Monitoring UIActivity Data Receiving)演示了如何观察 App 接收文件的过程,步骤如下:

  1. 从其他 App 向目标 App 分享一个文件,或通过 AirDrop、邮件发送;选择能触发"Open with..."对话框的文件类型(即没有默认打开 App 的类型,例如 PDF);
  2. 挂钩 open-URL 处理回调(application:openURL:options:,以及基于 Scene 的 App 的scene:openURLContexts:),以及根据Info.plist检查识别出的其他方法;
  3. 观察 App 行为;
  4. 此外,可以发送特定畸形文件或应用模糊测试技术。

以真实文件管理器为例:从另一台 Apple 设备(如 MacBook)通过 AirDrop 发送 PDF,在AirDrop弹窗中点击Accept。由于该文件没有默认打开 App,iOS 切换到Open with...弹窗:

选择目标 App 后,Frida 挂钩输出显示:

(0x1c4077000) -[AppDelegate application:openURL:options:] application: <UIApplication: 0x101c00950> openURL: file:///var/mobile/Library/Application%20Support /Containers/com.some.filemanager/Documents/Inbox/OWASP_MASVS.pdf options: { UIApplicationOpenURLOptionsAnnotationKey = { LSMoveDocumentOnOpen = 1; }; UIApplicationOpenURLOptionsOpenInPlaceKey = 0; UIApplicationOpenURLOptionsSourceApplicationKey = "com.apple.sharingd"; ... } RET: 0x1

可以看到:发送方是com.apple.sharingd,URL scheme 是file://,且用户一旦选中打开 App,系统就已把文件移动到了目标 App 的Inbox(Documents/Inbox/)。App 随后负责处理并删除 Inbox 中的文件——这个示例 App 把文件移动到/var/mobile/Documents/并从 Inbox 移除:

(0x1c002c760) -[XXFileManager moveItemAtPath:toPath:error:] moveItemAtPath: /var/mobile/Library/Application Support/Containers /com.some.filemanager/Documents/Inbox/OWASP_MASVS.pdf toPath: /var/mobile/Documents/OWASP_MASVS (1).pdf error: 0x16f095bf8 0x100f24e90 SomeFileManager!-[AppDelegate __handleOpenURL:] 0x100f25198 SomeFileManager!-[AppDelegate application:openURL:options:] ... RET: 0x1

从栈回溯可以看到调用链:application:openURL:options:→__handleOpenURL:→moveItemAtPath:toPath:error:。全部信息都在没有目标 App 源码的情况下获得——首步挂钩application:openURL:options:是明确的,其余步骤需要推断候选方法(例如包含 "copy"、"move"、"remove" 等字符串的方法)逐一追踪。这种接收文件的方式与自定义 URL scheme 的处理方式相同,可进一步参考 MASTG-TEST-0075。

自定义 Activity:UIActivity 子类与敏感数据处理

App 可以通过继承UIActivity提供自己的 Activity,并将实例通过applicationActivities参数传入,自定义 Activity 会与系统 Activity 一同出现在 Share Sheet 中。

一个自定义UIActivity在prepare(withActivityItems:)中接收被分享的 items,并在perform()中对它们采取行动。由于这两个方法的实现完全由 App 控制,自定义 Activity 可以对(可能敏感的)items 做任何事情,例如:

  • 上传到后端服务器;
  • 写入磁盘;
  • 记录日志。

任何处理敏感数据的自定义 Activity 都应遵循与 App 其余部分相同的数据存储、日志记录与网络通信安全要求。

安全测试视角:验证 App 的分享实现

除了理解 API 行为,MASTG 还提供了可直接落地的运行时检测手段。

发送端:挂钩初始化方法与排除属性

MASTG-TECH-0167 用 Frida 同时挂钩两个 Objective-C 方法:

  • initWithActivityItems:applicationActivities:—— 读取activityItems与applicationActivities;
  • excludedActivityTypesgetter —— 读取被排除的 Activity。

脚本如下:

Interceptor.attach( ObjC.classes. UIActivityViewController['- initWithActivityItems:applicationActivities:'].implementation, { onEnter: function (args) { printHeader(args) this.initWithActivityItems = ObjC.Object(args[2]); this.applicationActivities = ObjC.Object(args[3]); console.log("initWithActivityItems: " + this.initWithActivityItems); console.log("applicationActivities: " + this.applicationActivities); }, onLeave: function (retval) { printRet(retval); } }); Interceptor.attach( ObjC.classes.UIActivityViewController['- excludedActivityTypes'].implementation, { onEnter: function (args) { printHeader(args) }, onLeave: function (retval) { printRet(retval); } }); function printHeader(args) { console.log(Memory.readUtf8String(args[1]) + " @ " + args[1]) }; function printRet(retval) { console.log('RET @ ' + retval + ': ' ); try { console.log(new ObjC.Object(retval).toString()); } catch (e) { console.log(retval.toString()); } };

保存为inspect_send_activity_data.js后加载:

frida -U Telegram -l inspect_send_activity_data.js

以 Telegram 为例,分享一张图片时的输出:

[*] initWithActivityItems:applicationActivities: @ 0x18c130c07 initWithActivityItems: ( "<UIImage: 0x1c4aa0b40> size {571, 264} orientation 0 scale 1.000000" ) applicationActivities: nil RET @ 0x13cb2b800: <UIActivityViewController: 0x13cb2b800> [*] excludedActivityTypes @ 0x18c0f8429 RET @ 0x0: nil

分享一个文本文件时的输出:

[*] initWithActivityItems:applicationActivities: @ 0x18c130c07 initWithActivityItems: ( "<QLActivityItemProvider: 0x1c4a30140>", "<UIPrintInfo: 0x1c0699a50>" ) applicationActivities: ( ) RET @ 0x13c4bdc00: <_UIDICActivityViewController: 0x13c4bdc00> [*] excludedActivityTypes @ 0x18c0f8429 RET @ 0x1c001b1d0: ( "com.apple.UIKit.activity.MarkupAsPDF" )

对比可见:图片的 activity item 是UIImage且没有排除项;文本文件有两个不同的 activity item,且排除了com.apple.UIKit.activity.MarkupAsPDF。另一个 App 分享图片时则暴露了更多自定义 Activity 与排除项(输出已隐去来源 App 名称):

[*] initWithActivityItems:applicationActivities: @ 0x18c130c07 initWithActivityItems: ( "<SomeActivityItemProvider: 0x1c04bd580>" ) applicationActivities: ( "<SomeActionItemActivityAdapter: 0x141de83b0>", "<SomeActionItemActivityAdapter: 0x147971cf0>", "<SomeOpenInSafariActivity: 0x1479f0030>", "<SomeOpenInChromeActivity: 0x1c0c8a500>" ) RET @ 0x142138a00: <SomeActivityViewController: 0x142138a00> [*] excludedActivityTypes @ 0x18c0f8429 RET @ 0x14797c3e0: ( "com.apple.UIKit.activity.Print", "com.apple.UIKit.activity.AssignToContact", "com.apple.UIKit.activity.SaveToCameraRoll", "com.apple.UIKit.activity.CopyToPasteboard", )

无源码时的静态定位

如果只有编译/安装后的 App,可以用 MASTG-TOOL-0129(rabin2)在二进制中搜索相关方法字符串:

$ rabin2 -zq Telegram\ X.app/Telegram\ X | grep -i activityItems 0x1000df034 45 44 initWithActivityItems:applicationActivities:

小结与安全清单

  • 发送端:审查UIActivityViewController的三个关键输入——activityItems(分享什么)、applicationActivities(自定义服务做什么)、excludedActivityTypes(排除了哪些内置类型);
  • 排除不是防护:excludedActivityTypes无法排除第三方分享扩展,因此绝不能把它当作敏感数据的保护机制;是否分享某类数据属于用户授权决策;
  • 接收端:核对Info.plist中的UTExportedTypeDeclarations/UTImportedTypeDeclarations与CFBundleDocumentTypes,确认 App 声明的可打开文件类型是否过宽;检查application(_:open:options:)/scene(_:openURLContexts:)是否校验收到的 URL 与文件内容;
  • Inbox 清理:确认 App 处理完Documents/Inbox/中的文件后及时删除,避免敏感文件滞留沙盒;
  • 自定义 Activity:检查prepare(withActivityItems:)与perform()的实现,确认其上传、落盘、日志等行为遵循与主 App 一致的数据存储、日志与网络通信安全规范。

更深入的内容可继续阅读本仓库中关联的 MASTG-TECH-0167、MASTG-TECH-0168 与已废弃的 MASTG-TEST-0071,以及知识库中其他 iOS 平台交互类文章。

  • 文档
  • 教程
  • 网络安全

【免费下载链接】mastg

The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.

项目地址:https://gitcode.com/gh_mirrors/ow/mastg
点击查看免费下载
上一篇:10分钟快速上手:使用SGLang在昇腾Atlas 800上运行Qwen3-Next-80B-A3B-Instruct大模型
下一篇:解决TMPEffects常见问题:Unity文本动画插件排错与性能优化

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询