這裏網上的朋友已經介紹的很詳細了,具體的連接已經沒法找到了。html
這裏主要說幾點本人在開發中遇到的問題:ios
1.漏單必需要處理,玩家花RMB購買的東西卻丟失了,是絕對不能容忍的。所謂的漏單就是玩家已經正常付費,卻沒有拿到該拿的道具。json
解決:只要購買成功,便將購買記錄(receipt等帳單信息)保存下來,而後將帳單信息傳送給咱們遊戲服務器,遊戲服務器得到帳單後,和蘋果服務器驗證,帳單有效的話,回饋給遊戲服務器處理,遊戲服務器處理後,返回給遊戲客戶端處理,處理完畢,將本地保存的購買記錄刪除。安全
2.漏單的檢測位置服務器
解決:網絡
2.1 作法1:在任意購買成功以後,順便檢測一次漏單,有漏單數遍處理了。app
2.2 作法2:是在遊戲登錄的時候檢測一次漏單,即循環檢測漏單數據,挨個發送給服務器驗證處理,直到將全部的漏單處理完畢。這是緣由是購買服務器未返回結果而客戶端崩潰的狀況下,玩家再次登錄,會產生漏單。ide
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 .用本身的服務器的記錄帳單列表對比