为啥不应该直接调用收据验证端点
Posted
技术标签:
【中文标题】为啥不应该直接调用收据验证端点【英文标题】:Why one should not call receipt validation endpoint directly为什么不应该直接调用收据验证端点 【发布时间】:2020-01-19 03:17:51 【问题描述】:Apple 提供了一个端点来验证收据: https://buy.itunes.apple.com/verifyReceipt 并警告不要从应用程序调用端点
不可能在用户的 设备和 App Store 直接因为你不控制任何一端 该连接的,因此可能容易受到 中间人攻击。
据说,安全的方法是先将收据发送到“我自己的”服务器,然后从自己的服务器与 Apple 端点通信。
老实说,我不明白提高安全级别有何帮助。是的,我不控制/verifyReceipt
端点,但苹果希望可以。为什么
手机我的服务器苹果服务器比手机苹果服务器好吗?
您能否从黑客(或中间人)的角度详细说明这一点?在后一种情况下,他将如何篡改收据/回复,在前一种情况下对他来说有什么困难?
【问题讨论】:
【参考方案1】:更改应用程序二进制文件以更改应用程序内的字符串相对容易。如果您的二进制文件包含字符串“https://buy.itunes.apple.com/verifyReceipt”,那么攻击者可以将字符串更改为“https://example.com/verifyReceipt”(受其控制的服务器)并让服务器返回收据 JSON,这使得购买看起来像是成功的。这是一种易于自动化的攻击,因此您只需通过脚本运行二进制文件,该脚本将 Apple URL 的所有实例替换为另一个 URL。
当您将自己的服务器与 Apple 通信时,您可以(相对)确定该连接是安全的。还有一些方法可以保护应用程序和您的服务器之间的通信,例如应用程序二进制文件中的证书,其中包含一个公钥,即您服务器上的私钥。 (我不是这方面的专家,所以关于键的细节可能不是 100% 正确的)。
话虽如此,攻击者还可以通过其他方式使其看起来像是通过了购买。他们可以在您的应用程序二进制文件中搜索常见的收据解析库并翻转已知的布尔值(例如 userCompletedPurchase
布尔标志)。这些攻击很容易编写脚本。
确保您的应用不受攻击的最佳方法是移除唾手可得的果实,并让常见脚本不会打开您的应用受到攻击变得更加困难。一种方法是不直接与 Apple 验证收据。
【讨论】:
假设我不是将请求发送到buy.itunes.apple.com/verifyReceipt,而是将它发送到我的服务器说my.secure.server.com/verifyReceipt。攻击者可以将(在应用程序二进制文件中)my.secure.server.com/verifyReceipt 替换为his.hacking.server.com/verifyReceipt,不是吗?这是否意味着唯一的区别是Apple的服务器URL广为人知,而我的URL却不那么为人所知,因此攻击者更难在应用程序的二进制代码中找到它? 是的,最大的问题是Apple的URL众所周知,攻击众所周知。这是一种非常基本的攻击,很可能在应用程序破解工具包中。使用您自己的服务器,您可以进行使用不同路径和 URL 的其他检查(例如,对始终以某些特定文本响应的 URL 的简单调用)。 我个人的观点是,使用Apple的URL并不是最严重的错误。设置自己的服务器既费时又费钱。您必须决定是否值得您因盗版而失去的销售数量。对于一个小型应用程序来说,除了作为一种学习体验之外,它可能不值得。 Apple 总是说你永远不应该在 WWDC 会议中直接使用 URL,但我认为如果你意识到风险,你可以自己决定做什么。 只是一个想法(根本不了解该技术),如何实现简单的字符串检查以防止字符串交换? '让 url = "buy.itunes.apple.com/verifyReceipt";如果 url[2] != "y" ||网址[5] == "t" || ...然后拒绝”。至少乍一看,它应该阻止简单的字符串替换尝试工作。或者二进制替换可以处理这个?【参考方案2】:我认为您引用但未包含的 Apple 文档部分的关键部分是之前的句子。
使用您自己的服务器可以让您设计自己的应用程序以识别和信任 只有您的服务器,并让您确保您的服务器与 App Store 服务器。
尤其是那句话的前半部分(强调我的)。我认为这是来自 Apple 的一点推动,即应用程序应设计为“仅识别和信任您的服务器”。
在最简单的情况下(即最小),可以使用他们的服务器作为代理来访问 Apple 的服务器。服务器可以简单地将 Apple 的有效负载传回应用程序,或者发送一些简单的 JSON,例如
success: true
或者甚至可能只是发送 200 响应一样懒惰。
使用 MITM,可以根据需要轻松更改响应。因此,即使您正在使用您的服务器,此时唯一的障碍是攻击者需要确定您的服务器的有效响应是什么样的。
他们可以通过简单地发送错误收据然后查看响应来解决问题。或者,黑客可能会 TOFFT 并进行购买以获得有效响应,然后提供给其他人以便他们获利。
这是直接去Apple上面的“一步”,因为每个人都知道Apple的payload是什么。因此,如果应用程序直接转到 Apple,那么某人能够更轻松地运行 MITM 并复制有效的收据响应。
回到 Apple 所写的内容,他们鼓励您设计一种更强大的设计,以帮助减少潜在的虚假购买行为的发生。这种稳健性可以为您提供更多保护。
这可以采取多种形式。
例如,您的服务器可能会以加密格式发回响应。或者用哈希回复。如果您的应用程序在使用过程中依赖于您的服务器,那就更好了,因此服务器可以作为事实。或者,该应用程序可能会定期“打电话回家”以获得特权配置。有很多方法可以让黑客更难对付。
Apple 将由您决定如何确定与您的服务器建立的信任。毕竟是你的“钱”。
例如,我最近制作的游戏是专门为使用服务器而构建的。所以所有的动作都要经过服务器(游戏是在服务器上模拟的)。虽然有人当然可以修改应用程序,但最终服务器理论上应该纠正引入的任何错误。
请注意,仍然有可能有人可以绕过更强大的安全措施。
【讨论】:
【参考方案3】:您可以在 ios 设备上验证 iOS 收据。但是您不能确定收据是否真的有效。用户可能已经入侵了设备,让您认为收据是有效的。
您的用户可以编辑您应用的可执行代码,也可以编辑操作系统。借助 Apple 采购系统等通用/共享 API,用户可以在自己的手机上运行一些公开可用的工具来避免付费。
但是,您的服务器由您控制。您的客户无法实际访问它。因此,您的服务器(希望如此!)不会被黑客入侵。与设备不同,这意味着您的服务器可以被信任。当您的服务器与 Apple 的服务器建立 SSL 连接时,您就知道您确实在与 Apple 的服务器通信。不是您的用户为了绕过应用内购买而安装的。
更新
假设您在用户购买了您的consumable product
后获得了您的Receipt
。所以现在你想验证它,你有两个选择:
1.本地收据验证(从用户设备)。
2。通过您的服务器进行收据验证。
本地验证:
收到收据后,您可以通过应用程序中的verifyReceipt 端点传递receipt
文件的内容。你会得到一个响应,包括来自这个endpoints
的可读的JSON
正文。根据此响应,您可以验证收据并控制用户操作。
所有这一切都发生在您的应用[用户设备]中。发布您的应用程序后,如果没有另一个版本,您将无法修改您的应用程序(如果需要)。此外,用户对其设备的控制权比您多。
通过您的服务器验证:
得到Receipt data
后,需要对数据进行Base64 编码。将此 Base64 编码的数据发送到您的服务器。
在您的服务器上,创建一个 JSON 对象,其中包含收据数据、密码(如果收据包含自动更新订阅)和 requestBody 中详述的 exclude-old-transactions 键。将此 JSON 对象作为 HTTP POST 请求的负载提交。在测试环境中,使用https://sandbox.itunes.apple.com/verifyReceipt作为URL。在生产环境中,使用 https://buy.itunes.apple.com/verifyReceipt 作为 URL。
现在您将从 App Store 获得 JSON 对象响应,其中包含 responseBody 中详述的键和值。根据响应,您可以验证收据并向应用发送响应以进行进一步操作。
因此,如果用户在您的应用中购买了某些东西,您不需要将所购买的东西存储在应用中。您希望将其存储在服务器上,并且该服务器仅在与 Apple 的服务器验证收据后才会将购买的数据发送到设备。
而且您在服务器中拥有比您的应用更多的控制权,您还可以随时更改任何有关收据验证的机制(无需更新您的应用)并从服务器控制您的用户。
希望你能得到它。现在就看你喜欢哪一种了。
【讨论】:
假设我没有将请求发送到buy.itunes.apple.com/verifyReceipt,而是将其发送到我的服务器,例如my.secure.server.com/verifyReceipt。攻击者可以将(在应用程序二进制文件中)my.secure.server.com/verifyReceipt 替换为his.hacking.server.com/verifyReceipt,不是吗?这是否意味着唯一的区别是Apple的服务器URL广为人知,而我的URL却不那么为人所知,因此攻击者更难在应用程序的二进制代码中找到它?【参考方案4】:由于我深入参与自动续订订阅工作流程,因此我将尝试在这里表达我的理解。
为什么那个端点在那里?目的是什么?
该 API 的目的是验证用户使用您的应用进行的购买。那么为什么要从手机(电话)调用该 API。在那种环境中,您已经知道该用户已经进行了购买。
但如果您想调用该 API 来解码应用内的编码收据(以读取重要值),那么请考虑另一种推荐的方法。该编码收据是 PKCS7 编码的,Apple 本身提供了 lib 来解码它。
希望对你有帮助
【讨论】:
以上是关于为啥不应该直接调用收据验证端点的主要内容,如果未能解决你的问题,请参考以下文章
在哪里可以找到 iOS App Store 收据验证的共享密钥?
为啥我应该使用 Ext.dispatch 而不是直接调用控制器代码?