查看 Apple 的服务器购买模型图。
在第 9 步中,服务器如何知道它真的在与有权购买的 iPhone 通话,并且 Eve 没有使用不诚实获得的收据进行重播?
收据可能是有效的,但这并不能证明发件人是有资格的一方。
iPhone上是否有任何可用于签署收据的设备证书概念?
有没有办法将收据绑定到设备,或者将收据绑定到iTunes帐户和设备,以便服务器可以验证?
查看 Apple 的服务器购买模型图。
在第 9 步中,服务器如何知道它真的在与有权购买的 iPhone 通话,并且 Eve 没有使用不诚实获得的收据进行重播?
收据可能是有效的,但这并不能证明发件人是有资格的一方。
iPhone上是否有任何可用于签署收据的设备证书概念?
有没有办法将收据绑定到设备,或者将收据绑定到iTunes帐户和设备,以便服务器可以验证?
Apple 提供的易受攻击的方法
服务器可以通过执行以下操作来验证购买:
transactionReceipt
iPhone 应用程序在购买后收到一个。让 iPhone base64对其进行编码(您可以使用 NSData 的这个开源补充)并将其发送到您的服务器。(您甚至可以按原样发送它,并让服务器在验证之前对其进行 base64 编码。)
让您的服务器使用receipt-data
带有 base64 编码的单个密钥发送 JSON 请求,transactionReceipt
以 https://buy.itunes.apple.com/verifyReceipt
使用 HTTP POST。(有关如何以各种服务器端语言执行此操作的说明,请参阅此站点)
服务器将响应一个带有两个键的 JSON 对象:status
一个是整数,receipt
另一个是重复的收据。
如果状态为零,则应接受有效收据,非零值表示收据无效。
Apple 方法的安全补充
但是,存在一些安全隐患。用户可以使用另一个用户的收据,因为设备没有绑定到收据,或者用户可以使用另一个产品的收据,因为服务器不验证收据的产品 ID。为确保不会发生这种情况,您还应该执行以下操作:
当您第一次在应用程序中获得收据时,请立即通过安全通道(例如 HTTPS 或 SSL 套接字)将其与设备的 UUID一起发送到您的服务器。不要将其存储在任何地方,将其留在内存中。
在您的服务器上,将 UUID 和收据对存储在数据库中。
当设备发送 UUID 和收据对时,请使用您的数据库验证收据尚未被使用,并通过检查收据的产品 id确保收据实际上是您的产品。收据只是一个 JSON 对象,因此您的服务器可以通过从 base64 解码收据来读取内容。
通过安全通道向设备返回响应,告知其购买是否为:
由于收据只存在于设备的内存中,并且您的应用程序使用设备的 UUID(可能被越狱设备欺骗,请参阅评论),并且您的所有产品购买都以安全的方式记录在您的服务器上的设备 UUID ; 用户不能使用其他用户的收据来验证购买,他们也不能使用其他产品的收据,因为您会检查它。
如果您想验证交易的其他详细信息,您还可以验证收据中的其他字段。例如,如果您的产品是订阅产品,您还想查看交易日期。
此外,用户不能通过将设备放在与您的主机同名的私有网络上来假装是您的服务器,因为他们不会拥有您的 SSL 证书。
故障注意事项
由于在用户的设备获取收据和与您的服务器验证之间可能会发生故障(例如,如果用户失去连接,或者您的服务器因维护而停机),您还应该让用户“重新授权”。重新授权应该从商店获取收据(使用Restored Transaction)并将其重新发送到服务器,就好像这是一次新购买一样。这应该很少需要使用,但应该可以在网络故障的情况下节省用户重新购买产品的时间。
多设备考虑
这意味着如果用户想要在多个设备上使用应用程序,他们将不得不多次购买该产品。这可能是预期的效果,但您可能应该在用户购买之前通知他们,因为他们可能希望能够在与他们的帐户关联的设备上使用内容。
如果收据还包含 iTunes 帐户信息,则身份验证可以使用该信息来允许用户在他们的所有设备(但不是他们的朋友)之间共享内容。
我不认为可以将收据绑定到设备。
我的理解是,您可以在多个设备上安装应用程序而无需额外费用。将其绑定到设备意味着如果您升级/更换手机,您将需要再次购买所有应用程序。
我相信,如果您无法读取用户的 Apple ID,那么您对盗版的唯一保护就是跟踪(当然是服务器端)每个 transaction_id 的下载请求数量,并在它们超过某个值时限制它们。
因此,如果您将其限制为 50,这为用户在多个设备上部署应用程序及其内容并多次恢复提供了合理的余地,但对于想要无限分发具有有效收据的盗版版本的人来说,这将变得困难恢复。当然,他们可以只分发包含您所有内容的版本,但您对此无能为力,至少他们不会对您的服务器征税。
Beniot 的回答很好,但是,这些天,正如 Joe D'Andrea 所提到的,UDID 已被弃用,我上次尝试时,一个使用调用获取 UDID 的应用程序在上传到 iTunes 期间未能通过验证。
要补充 hloupyhonza 的答案,除了为特定收据设置“下载请求”计数器外,您还可以按时间限制收据的有效性。我发现 12 到 24 小时之间的任何时间都是合理的。
这种方法还允许购买者在他拥有的任何其他设备上使用购买,只要他使用相同的 Apple ID 登录 App Store。注意:每次恢复购买完成时,Apple 都会返回一张全新的收据(包含原始收据的详细信息) - 这允许在我们为特定收据设置的时间限制之后恢复购买。
为了防止典型的“谷歌搜索”黑客解决方案(我的数据显示这构成了几乎所有的 IAP 黑客尝试),我使用了以下串联的校验和(选择你最喜欢的算法,没关系,除非你想让它无懈可击):
该应用程序将验证我们的验证服务器返回的校验和。但这并不是无懈可击的,因为黑客可能会从您的应用程序的二进制文件中检索共享密钥。但到目前为止,它已经阻止了所有“现成的”黑客攻击,这对我来说已经足够了。