這里網上的朋友已經介紹的很詳細了,具體的鏈接已經無法找到了。
這里主要說幾點本人在開發中遇到的問題:
1.漏單必須要處理,玩家花RMB購買的東西卻丟失了,是絕對不能容忍的。所謂的漏單就是玩家已經正常付費,卻沒有拿到該拿的道具。
解決:只要購買成功,便將購買記錄(receipt等賬單信息)保存下來,然后將賬單信息傳送給我們游戲服務器,游戲服務器獲得賬單后,和蘋果服務器驗證,賬單有效的話,回饋給游戲服務器處理,游戲服務器處理后,返回給游戲客戶端處理,處理完畢,將本地保存的購買記錄刪除。
2.漏單的檢測位置
解決:
2.1 做法1:在任意購買成功之后,順便檢測一次漏單,有漏單數遍處理了。
2.2 做法2:是在游戲登陸的時候檢測一次漏單,即循環檢測漏單數據,挨個發送給服務器驗證處理,直到將所有的漏單處理完畢。這是原因是購買服務器未返回結果而客戶端崩潰的情況下,玩家再次登陸,會產生漏單。
3.漏單的版本兼容
漏單要做好版本兼容,eg.玩家購買英雄ID為100的英雄,產生了一次漏單,但是一直未再次登陸游戲,由於版權等原因,這個英雄在后期版本中被刪除了,如果玩家這是漏單處理,會在服務器獲得一個丟棄的英雄,產生數據異常。
我的處理是,如果是英雄,檢測英雄在本地hero.csv中是否有效,如果有效,檢測這個英雄是否已經擁有,如果沒有且數據正常,發送給服務器處理漏單,否則丟棄掉這條漏單。
還有說蘋果服務器漏單過期的說法,不過我沒有遇到過,沒做處理。
4.服務器和客戶端漏單對應順序
遇到過這種情況,客戶端產生了多個漏單,發送給游戲服務器驗證,游戲服務器請求蘋果服務,蘋果服務器返回的receipt的json數據中包含一個所有未處理的訂單列表,最后產生的購買數據在最后,客戶端的漏單順序和服務器的驗證順序要保持一致。
NOTE: The validated receipt may contain multiple transactions in the “in_app” parameter. It seems that Apple keeps all of the user’s transactions in the receipt in chronological order. Assuming users can only purchase one product at a time in your app, you want to grab the last transaction in the “in_app” array.
receipt的參數可以參考如下:
https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1
向蘋果服務器驗證收據返回的數據:
Status Description
0 The receipt provided is valid.
21000 The App Store could not read the JSON object you provided.
21002 The data in the receipt-data property was malformed.
21003 The receipt could not be authenticated.
21004 The shared secret you provided does not match the shared secret on file for your account.Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.
21005 The receipt server is not currently available.
21006 This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.
21007 This receipt is a sandbox receipt, but it was sent to the production server.
21008 This receipt is a production receipt, but it was sent to the sandbox server.
-------------------------------------------------------華麗麗的分割線-----------------------------------------------------------------------
這兩天我在籌備我們的游戲APP的內購,仔細考慮了幾個付費安全上的問題。凡是涉及到付費的問題都很敏感,任何一方出現損失都是不能接受的,所以在這里整理一些支付安全的要點分享一下。IAP是指In-App Purchase, 是一種付費方式,而並不是蘋果專有的付費方式,在其它平台上也會有不同的實現,這里針對Apple IAP。
說到IAP安全問題,在蘋果的IAP流程中有一個比較明顯的邏輯漏洞,這個邏輯漏洞是建立在我們處理不當的情況下發生的,會導致己方提供的服務和玩家之間出現問題。先看看IAP支付時序圖:
整個支付流程如下:
1.客戶端向Appstore請求購買產品(假設產品信息已經取得),Appstore驗證產品成功后,從用戶的Apple賬戶余額中扣費。
2.Appstore向客戶端返回一段receipt-data,里面記錄了本次交易的證書和簽名信息。
3.客戶端向我們可以信任的游戲服務器提供receipt-data
4.游戲服務器對receipt-data進行一次base64編碼
5.把編碼后的receipt-data發往itunes.appstore進行驗證
6.itunes.appstore返回驗證結果給游戲服務器
7.游戲服務器對商品購買狀態以及商品類型,向客戶端發放相應的道具與推送數據更新通知
這七個步驟實際上是一個很安全的流程了。那問題出在哪里呢?我們談談兩種蘋果IAP的驗證模型。
IAP built-in Model,本地驗證
有些單機游戲甚至是網游,都直接跳過了3~7步驟,在第2步拿到receipt-data之后,直接由客戶端向itunes.appstore發送驗證請求,並且拿到結果,根據結果修改游戲數據。
我們在設計游戲的時候都遵循一個真理,“凡是在客戶端的數據都是不安全的”,深以為然。如果沒有獨立服務器輔助驗證,這樣也就避免不了數據被修改的事實了,是的,你會少賺錢。不過如果網游也不通過獨立服務器驗證,而是在客戶端驗證之后再告知服務器狀態讓其發放游戲道具,那就太可怕了點。這是IAP built-in Model,經常出現安全問題的邏輯如下:
?
1
2
3
4
5
6
7
voidpaymentQueue(...)
{
if(transaction != nullptr)
{
me.money += 1000;
}
}
上面的代碼在接收到付費成功的response就直接給游戲發放商品,不對產品和單據進行驗證。如果receipt-data允許放在本地驗證,就可能發生我們說的免費內購的BUG. 而實際上也真的有類似IAPCracker/IAPFree等工具專門利用這樣的IAP漏洞的。而對於已經越獄了的iOS設備就太簡單了,甚至不需要通過偽造或者跳過receipt-data驗證就可以修改本地數據達到目的。
那是不是就完全不能讓這個過程變得安全了呢?也不是,但這個安全保障只是讓修改變得困難而已。蘋果官方提供了 Validating Receipts Locally 在客戶端對receipt-data進行安全驗證,主要是對證書以及簽名的合法性驗證。如果不想自己寫代碼驗證,也可以借助第三方機構提供的receipt-data驗證API,比較著名的有 urbanairship和 beeblex 。
但如果能偽造一個完全合法的receipt-data,是不是一樣可以達到欺騙目的。是的,為了繞過Validating Locally,於是黑客開始用自己偽造的receipt-data進行移花接木,所以出現了可以偽造”合法訂單”的 in-appstore 。因此這種本地加強驗證的方法也不能完全避免IAP攻擊。
IAP Server Model,服務器驗證
而如果我們把驗證邏輯移到服務器上,這個過程就變得容易多了。因為不再需要擔心receipt-data被偽造的問題。不過就算把步驟4~7在服務器上做了,同樣也會產生一些幼稚的邏輯漏洞:
對驗證receipt-data的reponse content不進行驗證和記錄,只根據Product直接發放商品。這樣只要客戶端不斷提交receipt-data,按照正常邏輯你就需要不斷驗證並且重復發放商品。較為安全的做法是:
在每一次收到receipt-data之后,都把提交的玩家賬號以及receipt-data中的單號建立映射並記錄下來,在每次驗證receipt-data時,先判斷其是否已經存在。
只要做了這樣的驗證,整個支付流程都變得明朗起來。
確保receipt-data的成功提交與異常處理
建立在IAP Server Model的基礎上,並且我們知道手機網絡是不穩定的,在付款成功后不能確保把receipt-data一定提交到服務器。如果出現了這樣的情況,那就意味着玩家被appstore扣費了,卻沒收到服務器發放的道具。
解決這個問題的方法是在客戶端提交receipt-data給我們的服務器,讓我們的服務器向蘋果服務器發送驗證請求,驗證這個receipt-data賬單的有效性. 在沒有收到回復之前,客戶端必須要把receipt-data保存好,並且定期或在合理的UI界面觸發向服務端發起請求,直至收到服務端的回復后刪除客戶端的receipt賬單記錄。這里就是我在開頭提到的漏單處理了。
如果是客戶端沒成功提交receipt-data,那怎么辦?就是玩家被扣費了,也收到appstore的消費收據了,卻依然沒收到游戲道具,於是投訴到游戲客服處。
這種情況在以往的經驗中也會出現,常見的玩家和游戲運營商發生的糾紛。游戲客服向玩家索要游戲賬號和appstore的收據單號,通過查詢itunes-connect看是否確有這筆訂單。如果訂單存在,則要聯系研發方去查詢游戲服務器,看訂單號與玩家名是否對應,並且是否已經被使用了,做這一點檢查的目的是 為了防止惡意玩家利用已經使用過了的訂單號進行欺騙(已驗證的賬單是可以再次請求驗證的,曾經為了測試,將賬單手動發給服務器處理並成功),謊稱自己沒收到商品。這就是上面一節IAP Server Model中紅字所提到的安全邏輯的目的。當然了,如果查不到這個訂單號,就意味着這個訂單確實還沒使用過,手動給玩家補發商品即可。
有朋友問怎么通過itunes-connect查看具體訂單,itunes-connect中無法直接看到訂單信息,可以用以下方法來查詢
1.可以通過賬單向蘋果發送賬單驗證,有效可以手動補發
2 .用自己的服務器的記錄賬單列表對比
3.利用第三方的TalkingData等交易函數,會自動記錄賬單數據
---------------------
作者:Teng的世界
來源:CSDN
原文:https://blog.csdn.net/teng_ontheway/article/details/47023119
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!