1. 程式人生 > >iOS應用內支付(IAP)開發中後期的那些坑

iOS應用內支付(IAP)開發中後期的那些坑

一,Product ID無效?

好了,經過前面的準備後,就到了真正和IAP聯通的步驟了。在輸入一個Product ID向伺服器發起request的時候,很有可能出現失敗的情況,在request屬性InvalidateIdentifier中,你會發現這個Product ID是無效的。

為什麼呢?蘋果是不會告訴你的,連個錯誤程式碼都沒有,非常坑爹。

所以這裡我們有一個Check List,需要大家逐條檢查:

Have you enabled In-App Purchases for your App ID?

Have you checked Cleared for Sale for your product?

Have you submitted (and optionally rejected) your application binary?

Does your project’s .plist Bundle ID match your App ID?

Have you generated and installed a new provisioning profile for the new App ID?

Have you configured your project to code sign using this new provisioning profile?

Are you building for iPhone OS 3.0 or above?

Are you using the full product ID when when making an SKProductRequest?

Have you waited several hours since adding your product to iTunes Connect?

Are your bank details active on iTunes Connect? (via Mark)

Have you tried deleting the app from your device and reinstalling? (via Hector, S3B, Alex O, Joe, and Alberto)

Is your device jailbroken? If so, you need to revert the jailbreak for IAP to work. (via oh my god, Roman, and xfze)

If you answered “No” to any one of these questions, there’s your problem.

If you answered “Yes” for each of these questions and you still have an invalid product ID, then you have a problem I haven’t seen before. Check out the links in the next section, several of which are Developer Forum posts that were especially helpful in my hunt for debugging invalid product IDs.

PS:再使用別人提供的例子程式碼測試IAP完成以後,這裡向你介紹一個別人封裝好的類庫:ECPurchase


二,驗證是否購買成功?

蘋果方就很負責的告知:我們的伺服器不穩定。真正開發之後,發現蘋果方果然是很負責的,不僅是不穩定,而且足夠慢。app store server驗證一個收據需要3-6s時間。

1.使用者能否忍受3-6s的等待時間

2.如果app store server 宕機,如何確保成功付費的使用者能夠得到正常服務。

對於第一個問題,我們有理由相信使用者完全無法忍受,所以採用非同步驗證的方式,伺服器收到客戶端的請求後,就將請求放到MCQ中去處理。

對於第二個問題,由於蘋果人員很負責人的告知:我們的伺服器不穩定,所以不排除收據驗證超時的情況。對於驗證超時的收據,儲存到資料庫中並標記為驗證超時,定時任務每隔一定的時間去app store驗證,確保能夠獲取收據的驗證結果。

在開發過程中,需要測試應用是否能夠正常的進行支付,但是又不能進行實際的支付,因此需要使用蘋果提供的sandbox Store測試。Store Kit不能在iOS模擬器中使用,測試Store必須在真機上進行。

在sandbox中驗證receipt

https://sandbox.itunes.apple.com/verifyReceipt

在生產環境中驗證receipt

https://buy.itunes.apple.com/verifyReceipt

在實際開發過程中,伺服器端通過issandbox欄位標識客戶端傳遞的收據是沙盒環境中的收據還是生產環境中的收據。在提交蘋果稽核前,沙盒測試均無問題。提交蘋果稽核後,被告知購買失敗,稽核未通過。通過查詢日誌發現,客戶端傳送的交易收據為沙盒收據,但是issandbox欄位卻標識為生產環境。

結論:蘋果稽核app時,仍然在沙盒環境下測試。但是客戶端同事在app提交蘋果稽核時,將issandbox欄位寫死,設定為生產環境。這樣就導致沙盒收據傳送到https://buy.itunes.apple.com/verifyReceipt去驗證。

那麼如何自動的識別收據是否是sandbox receipt呢?

識別沙盒環境下收據的方法有兩種:

1.根據收據欄位 environment = sandbox。

2.根據收據驗證介面返回的狀態碼

如果status=21007,則表示當前的收據為沙盒環境下收據, t進行驗證。

蘋果反饋的狀態碼;

21000App Store無法讀取你提供的JSON資料
21002 收據資料不符合格式
21003 收據無法被驗證
21004 你提供的共享金鑰和賬戶的共享金鑰不一致
21005 收據伺服器當前不可用
21006 收據是有效的,但訂閱服務已經過期。當收到這個資訊時,解碼後的收據資訊也包含在返回內容中
21007 收據資訊是測試用(sandbox),但卻被髮送到產品環境中驗證
21008 收據資訊是產品環境中使用,但卻被髮送到測試環境中驗證

先生產驗證後測試驗證,可以避免來回切換介面的麻煩。測試驗證只要用你自己申請的測試appid的時候才會用到,使用者不會擁有測試appid,所以不會走到測試驗證這一步。即使生產驗證出錯,應該也不回返回21007狀態嗎。測試驗證通過的使用者名稱,和充值金額最好用資料庫記錄下來,方便公司資金核對。

三,IAP 稽核相關的坑

IAP型別錯誤

由於我們是按月付費的產品,所以在設定IAP型別時,我沒有經驗,只是簡單設定成了可重複消費(Consumable)的IAP專案。但是我不知道,蘋果對於這種按時間收費的產品,應該使用不可更新的定閱(Non-Renewing Subscription)型別。這個型別設定錯誤造成了我們app的一次稽核被拒。

IAP驗證邏輯

由於蘋果在iOS5.0以下有IAP的bug,使得攻擊者可以偽造支付成功的憑證。而iOS6.0的系統在越獄後同樣可以偽造憑證,所以我們對於應用內支付,增加了伺服器端的驗證。 伺服器端會將支付憑證發給蘋果的伺服器進行二次驗證,以保證憑證是真實有效的。

在我們公司的測試伺服器中,我們會連線蘋果的測試伺服器(https://sandbox.itunes.apple.com/verifyReceipt)驗證。

在我們部署在線上的正式伺服器中,我們會連線蘋果的正式伺服器(https://buy.itunes.apple.com/verifyReceipt )驗證。

我們提交給蘋果稽核的是正式版,我們以為蘋果稽核時,我們應該連線蘋果的線上驗證伺服器來驗證購買憑證。結果我理解錯了,蘋果在稽核App時,只會在sandbox環境購買,其產生的購買憑證,也只能連線蘋果的測試驗證伺服器。但是稽核的app又是連線的我們的線上伺服器。所以我們這邊的伺服器無法驗證通過IAP購買,造成我們app的又一次稽核被拒。

解決方法是判斷蘋果正式驗證伺服器的返回code,如果是21007,則再一次連線測試伺服器進行驗證即可。蘋果的這一篇文件上有對返回的code的詳細說明。

IAP上線後的遇到的情況

我們在伺服器端增加了驗證IAP是否有效的邏輯。在產品上線後,如我們所料,我們收到了大量的欺騙性購買,這些都被我們的伺服器識別出來了,但是我們也遇到了以下這次沒有想到的情況:

1、由於國內越獄使用者的比例比較大(大概為50%),所以雖然我們伺服器會驗證購買憑證,但是每天有超過50%以上的憑證都是偽造的。同時由於蘋果的驗證伺服器在美國,憑證驗證請求響應的時間比較慢,大量的偽造憑證發給蘋果伺服器,不知道會不會被蘋果認為我們是在惡意進行DDOS。至少我們發現有些時候,驗證請求會超時。

2、由於國內有許多小白使用者,他們的手機從購買時就被渠道商幫忙越獄過了並且安裝了IAP free外掛。所以對於這類使用者,他們即使想付費購買,由於系統原有的IAP支付功能已經被破壞,所以他們是無法正常付費的。麻煩的是,他們會以為這是我們的app的問題,轉而給我們的客服打電話投訴。這讓我們非常鬱悶。

3、蘋果的驗證伺服器有時候會出問題,我們發現本來約定好返回的JSON資料在有幾次返回的居然是一個XML格式的檔案。造成我們將正常的付費IAP憑證驗證失敗。所以,在伺服器記錄下所有的驗證憑證非常有必要,一來可以防止黑客多次提交同一個成功憑證的重放攻擊,二來在需要時可以手工進行再驗證。

越獄手機可能被黑客竊取購買憑證!!

我們發現有一部分使用者反饋說已經收到蘋果的扣費賬單,但是我們從伺服器的驗證記錄看,他上傳的憑證卻是虛假的。由於這些使用者不太多,我們一開始以為是使用者在惡意欺騙我們,後來我們讓他將蘋果的付費賬單郵件轉發給我們,以及將itunes的購買記錄截圖轉發給我們,我們越來越懷疑這裡面有一個黑色的產業鏈。越獄手機的正常購買憑證可能被黑客的惡意程式截獲,具體的攻擊方式我們討論了一下,其實就是被中間人攻擊,詳細的過程如下:

  1. 越獄手機的在被破解後,可能從一些破解渠道安裝了黑客的惡意程式。
  2. 黑客將越獄手機所有https請求都經過他的中間伺服器。
  3. 當有支付請求時,黑客先將請求發給蘋果伺服器,待蘋果將成功的憑證返回後,黑客將這個憑證替換成假的憑證,完全支付憑證的偷取。

或許有人會問,這個憑證拿來有什麼用呢?很簡單 ,因為蘋果為了保護使用者的隱私,支付憑證中並不包含任何使用者的apple id資訊,所以我們的app和伺服器無法知道這個憑證是誰買的,而只能知道這個憑證是真的還是假的。於是黑客就可以用這個憑證,在另外的賬號中通知我們完成了購買,而發來的驗證憑證又是真實的,所以我們的伺服器就會誤認為是黑客的賬號完成了購買,繼而把會員期算在黑客的賬號上。

再舉一個簡單的例子,你拿500塊錢買了順風優選的500元購物券,由於這個購物券是不記名的,所以順風優選無法知道是誰買的。如果這個購物券在發放過程中被人掉包,那麼偷購物券的人就可以拿這個偷來的真購物券來購物,而順風優選的卡因為是不記名的,所以也無法查證這件事情。在這個例子中,購物券的不記名和蘋果的支付憑證無賬號資訊是同一個道理。

鑑於以上情況,考慮到越獄手機不但不能成功支付,還會有安全問題,所以我們在新版中取消了越獄手機中的IAP支付功能。

所以,請大家還是不要越獄自己的手機,iphone手機越獄後風險相當大。實在不值得為了免費玩幾個遊戲就丟掉安全性。

後記

中間人攻擊的演示

壞人在購買過程中插了一腿,換走了使用者的無記名發票(購物小票形象些),然後手持無記名小票偽裝成真實顧客或者轉手出售獲利。

關於越獄與盜版

不少細心的同學評論糾正我,指出越獄並不等同於使用盜版。確實,如果說嚴格的定義,越獄只是讓iPhone獲得root許可權,進而可以做任何事情。如果越獄的同學在越獄後不安裝IAP free外掛,不使用app sync外掛,不使用任何國內的和非bigboss的cydia源,不使用任何盜版軟體,所有應用都是從app store官方網站上下載的話,被黑客攻擊的可能性會降低一些。

即使這樣,由於手機已經被root了,蘋果的沙盒安全機制失效,所以風險還是很大的。

關於越獄使用者的比例

有同學提出我文章中寫的越獄手機比例太高了,想詢問資料來源。這個比例主要來自我們自己的app的統計資訊,以及結合國內的統計工具友盟的越獄手機比例統計,去年底國內的越獄比例是42%。