標籤:電訊廠商 帳號 記錄 一點 否則 es2017 blank 那是 機構
因業務需要實現了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的驗證模型。
驗證方式
1.IAP built-in Model,本地驗證
有些APP甚至是網遊,都直接跳過了3~7步驟,在第2步拿到receipt-data之後,直接由用戶端向itunes.appstore發送驗證請求,並且拿到結果,根據結果修改資料。
我們在設計APP的時候都遵循一個真理,“凡是在用戶端的資料都是不安全的”,深以為然。如果沒有獨立伺服器輔助驗證,這樣也就避免不了資料被修改的事實了,是的,你會少賺錢。
不過如果APP也不通過獨立伺服器驗證,而是在用戶端驗證之後再告知伺服器狀態讓其發放遊戲道具,那就太可怕了點。這是IAP built-in Model
那是不是就完全不能讓這個過程變得安全了呢?也不是,但這個安全保障只是讓修改變得困難而已。蘋果官方提供了 Validating Receipts Locally 在用戶端對receipt-data進行安全驗證,主要是對認證以及簽名的合法性驗證。如果不想自己寫代碼驗證,也可以藉助第三方機構提供的receipt-data驗證API,比較著名的有 urbanairship和 beeblex 。
但如果能偽造一個完全合法的receipt-data,是不是一樣可以達到欺騙目的。是的,為了繞過Validating Locally,於是駭客開始用自己偽造的receipt-data進行移花接木,所以出現了可以偽造”合法訂單”的 in-appstore 。因此這種本地加強驗證的方法也不能完全避免IAP攻擊。
2.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看是否確有這筆訂單。
如果訂單存在,則要聯絡研發方去查詢服務器,看訂單號與使用者名稱是否對應,並且是否已經被使用了,做這一點檢查的目的是 為了防止惡意使用者利用已經使用過了的訂單號進行欺騙(已驗證的賬單是可以再次請求驗證的,曾經為了測試,將賬單手動發給伺服器處理並成功),謊稱自己沒收到商品。
當然了,如果查不到這個訂單號,就意味著這個訂單確實還沒使用過,手動給使用者補發商品即可。
有朋友問怎麼通過itunes-connect查看具體訂單,itunes-connect中無法直接看到訂單資訊,可以用以下方法來查詢
1.可以通過賬單向蘋果發送賬單驗證,有效可以手動補發
2.用自己的伺服器的記錄賬單列表對比
3.利用第三方的TalkingData等交易函數,會自動記錄賬單資料
建議
為保證審核的通過,需要在用戶端或server進行雙步驟驗證,即,先以線上交易驗證地址進行驗證,如果蘋果正式驗證伺服器的返回驗證碼code為21007,則再一次串連沙箱測試伺服器進行驗證即可。
在應用提審時,蘋果IAP提審驗證時是在沙箱環境的進行的,即:蘋果在審核App時,只會在sandbox環境購買,其產生的購買憑證,也只能串連蘋果的測實驗證伺服器,如果沒有做雙驗證,需要特別注意此問題,否則會被拒。
其他
在sandbox中驗證receipt:https://sandbox.itunes.apple.com/verifyReceipt
在生產環境中驗證receipt:https://buy.itunes.apple.com/verifyReceipt
那麼如何自動的識別收據是否是sandbox receipt呢?
識別沙箱環境下收據的方法有兩種:
- 根據收據欄位 environment = sandbox。
- 根據收據驗證介面返回的狀態代碼。
如果status=21007,則表示當前的收據為沙箱環境下收據, 進行驗證。
蘋果反饋的狀態代碼
- 21000 App Store無法讀取你提供的JSON資料
- 21002 收據資料不符合格式
- 21003 收據無法被驗證
- 21004 你提供的共用密鑰和賬戶的共用密鑰不一致
- 21005 收據伺服器當前不可用
- 21006 收據是有效,但訂閱服務已經到期。當收到這個資訊時,解碼後的收據資訊也包含在返回內容中
- 21007 收據資訊是測試用(sandbox),但卻被發送到產品環境中驗證
- 21008 收據資訊是產品環境中使用,但卻被發送到測試環境中驗證
By Hgq
iOS內購 服務端票據驗證及漏單引發的思考.