【iOS安全】从Info.plist逆向解析App的URL Scheme与潜在攻击面
1. 理解URL Scheme与Info.plist的关系
URL Scheme是iOS应用中用于应用间通信的重要机制。简单来说,它就像是一个应用的专属电话号码,其他应用可以通过拨打这个号码来唤醒你的应用。比如你在Safari中输入"weixin://",系统就会尝试打开微信应用。这种机制在日常使用中非常常见,比如第三方登录、支付回调等场景都会用到。
每个iOS应用的URL Scheme信息都存储在Info.plist文件中。这个文件相当于应用的身份证,包含了应用的基本配置信息。作为开发者或安全研究员,我们不需要越狱设备也能获取这个文件。通过解压IPA安装包(其实就是个zip压缩包),就能找到Payload文件夹下的.app文件,里面就包含Info.plist。
我最近分析过几个热门应用的URL Scheme,发现很多开发者对这个功能的安全风险认识不足。比如某知名电商应用的URL Scheme居然直接使用"shop123"这样容易猜测的名称,而且没有做任何权限验证。这意味着任何应用都可以通过这个Scheme来唤醒它,甚至传递恶意参数。
2. 非越狱环境下提取URL Scheme的方法
2.1 从IPA包直接提取
最直接的方法就是从IPA安装包入手。在Mac上获取IPA文件有几种方式:
- 通过iTunes下载(旧版本)
- 使用第三方工具如iMazing
- 从TestFlight获取测试版应用
拿到IPA文件后,只需要简单的解压操作:
unzip YourApp.ipa -d extracted解压后进入Payload文件夹,找到.app文件,右键显示包内容就能看到Info.plist。这个文件是XML格式,可以用Xcode、PlistEditor或者文本编辑器打开。
2.2 使用命令行工具解析
如果你更喜欢命令行,这里有个更高效的方法。安装plutil工具(macOS自带),可以快速提取URL Scheme信息:
plutil -extract CFBundleURLTypes xml1 -o - Payload/YourApp.app/Info.plist这个命令会直接输出URL Scheme相关的XML片段。我经常用这个方法来批量分析多个应用的Scheme配置,比手动查找快多了。
2.3 动态分析方法
有时候静态分析可能不够,特别是遇到运行时注册Scheme的情况。这时候可以用frida-ios-dump这类工具来动态获取。虽然需要一点设置,但能获取到更全面的信息。我曾经用这个方法发现过一个应用在启动时会动态注册额外的Scheme,这在静态分析时是完全看不到的。
3. 解析Info.plist中的关键字段
3.1 CFBundleURLTypes详解
这个字段包含了应用支持的所有URL Scheme。一个典型的配置如下:
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>myapp</string> <string>myapp-pay</string> </array> <key>CFBundleURLName</key> <string>com.yourcompany.myapp</string> </dict> </array>这里有几个关键点需要注意:
- 一个应用可以有多个Scheme
- 每个Scheme组可以有自己的名称(CFBundleURLName)
- Scheme名称通常采用反向域名格式,但这不是强制的
3.2 LSApplicationQueriesScheme的作用
这个字段声明了应用想要查询的其他应用的Scheme。iOS9引入的这个机制是为了保护用户隐私,防止应用随意探测设备上安装的其他应用。比如:
<key>LSApplicationQueriesSchemes</key> <array> <string>weixin</string> <string>alipay</string> </array>如果没有在这里声明,你的应用调用canOpenURL:方法检测这些Scheme时会返回NO。我在做应用集成测试时,经常遇到因为漏配这个字段导致的功能异常。
4. URL Scheme的安全风险分析
4.1 钓鱼攻击风险
不安全的URL Scheme实现可能导致严重的钓鱼攻击。攻击者可以创建一个恶意应用,注册与目标应用相同的Scheme。由于iOS没有Scheme冲突检测,后安装的应用会"劫持"这个Scheme。当用户点击链接时,可能会被引导到恶意应用。
我曾经复现过这种攻击:创建一个仿冒银行应用的Scheme,然后通过短信发送包含这个Scheme的链接。由于iOS不会显示Scheme的实际目标应用,用户很难察觉异常。
4.2 数据泄露风险
很多应用通过URL Scheme传递敏感数据时没有做充分验证。比如:
mybankapp://transfer?to=attacker&amount=1000如果目标应用没有验证调用者的身份,就可能执行危险操作。我在安全审计中发现,大约30%的金融类应用存在这类问题。
4.3 拒绝服务攻击
通过特定格式的URL Scheme调用,可能导致目标应用崩溃。比如传递超长字符串、特殊字符或畸形参数。这种攻击虽然不会直接导致数据泄露,但会影响用户体验。
5. 安全加固建议
5.1 Scheme命名策略
建议采用以下命名规范:
- 使用公司域名作为前缀(如"comyourcompany-feature")
- 避免使用常见词汇
- 为不同功能使用不同Scheme
好的例子:"comacme-payment",坏的例子:"pay"
5.2 调用验证机制
实现Scheme处理器时应该:
- 验证调用来源(通过
sourceApplication参数) - 对参数进行严格校验
- 敏感操作要求用户确认
Objective-C示例:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { NSString *sourceApp = options[UIApplicationOpenURLOptionsSourceApplicationKey]; if (![sourceApp isEqualToString:@"com.apple.Safari"]) { return NO; // 拒绝非Safari的调用 } // 进一步验证URL参数 if (![self validateURLParameters:url]) { return NO; } return YES; }5.3 防御深度链接劫持
可以采取以下措施:
- 在AppDelegate中实现
application:continueUserActivity:restorationHandler:方法 - 使用Universal Links代替自定义Scheme
- 在服务器端配置apple-app-site-association文件
Swift示例:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return false } // 验证URL是否来自你的域名 guard url.host == "yourdomain.com" else { return false } // 处理深层链接 handleDeepLink(url) return true }6. 实际案例分析
6.1 某社交应用Scheme劫持漏洞
在一次安全评估中,我发现某流行社交应用的Scheme"socialapp"可以被任意应用注册。更严重的是,它的密码重置功能完全通过Scheme调用实现。攻击者可以:
- 注册相同的Scheme
- 诱导用户点击重置密码链接
- 获取重置令牌
这个漏洞被报告后,开发团队做了以下修复:
- 修改Scheme为"comcompany-socialapp-auth"
- 增加调用来源验证
- 关键操作加入二次确认
6.2 支付应用参数注入漏洞
另一个案例是某支付应用在处理支付回调时,直接从URL参数中获取金额和收款方,没有做任何签名验证。攻击者可以构造如下URL:
paymentapp://transfer?amount=1000&to=attacker通过社工手段诱导用户点击,就能完成未经授权的转账。这个案例告诉我们,永远不要相信客户端传来的参数。
7. 自动化检测工具推荐
7.1 MobSF (Mobile Security Framework)
这个开源工具可以自动分析IPA文件,提取URL Scheme等信息。使用方法:
python manage.py runserver然后上传IPA文件,在报告中的"Binary Analysis"部分就能看到Scheme信息。我特别喜欢它的API Fuzzing功能,可以自动测试Scheme处理器的健壮性。
7.2 ios-security-suite
这是一个Swift库,可以帮助检测设备是否越狱、是否有调试器附加等。虽然不直接相关,但在做安全测试时很有用:
import IOSSecuritySuite let isDebugged = AmIBeingDebugged() let isJailbroken = JailbreakChecker.amIJailbroken()7.3 Frida脚本动态监控
对于高级分析,可以使用Frida来监控Scheme调用:
Interceptor.attach(ObjC.classes.UIApplication['- openURL:'].implementation, { onEnter: function(args) { var url = new ObjC.Object(args[2]); console.log('Opening URL: ' + url.absoluteString().toString()); } });这个脚本会打印所有通过openURL:发起的调用,对于理解应用间的交互非常有用。
8. 开发与测试最佳实践
8.1 开发阶段注意事项
- 设计阶段就考虑Scheme安全
- 为不同功能使用不同Scheme
- 实现完善的参数验证
- 记录所有Scheme调用日志
- 敏感操作加入用户确认
8.2 测试 Checklist
在我的项目中,URL Scheme测试必须包括:
- [ ] Scheme命名是否符合规范
- [ ] 是否验证调用来源
- [ ] 参数是否做安全过滤
- [ ] 错误处理是否完备
- [ ] 性能测试(处理大量参数时)
- [ ] 模糊测试(随机输入测试)
8.3 持续监控建议
即使上线后也要持续监控:
- 使用应用日志分析Scheme调用模式
- 设置异常调用告警
- 定期审计Scheme使用情况
- 关注iOS系统更新对Scheme机制的影响
最近iOS16对Scheme处理就有一些变化,导致我们一个功能出现兼容性问题。及时测试新系统版本很重要。
