Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Don't steal coins in my App - Handle In-App Purchase validation from the server side

Sibevin
September 10, 2013

Don't steal coins in my App - Handle In-App Purchase validation from the server side

Sibevin

September 10, 2013
Tweet

Other Decks in Technology

Transcript

  1. 大綱 ▪ 基本概念 ▪ 什麼是In-App Purchase(IAP)? ▪ 我真的要用IAP嗎? ▪ 什麼是Third-Party

    Validation(TPV)? ▪ 實作 ▪ Server端處理IAP的運作流程 ▪ 接受App傳來的資訊 ▪ 資訊驗證 ▪ 三方驗證 ▪ 記錄交易內容,更新使用者權利 ▪ 回傳結果給App ▪ 其它
  2. 我真的要用IAP嗎? 優 ▪ 最直接的購買方式(IAP v.s. Payment System) ▪ 另一種產品的行銷管道 ▪

    支援IAP的驗證可以有效阻擋非法購買 缺 ▪ IAP抽非常非常非常重稅(30%) ▪ IAP偏向低價策略,獲益受到限制 ▪ 沒在賣東西,廣告才是收入來源 ▪ 沒有開發Native App的經驗
  3. 接受App傳來的資訊 我怎麼知道「驗證需要用到哪些資訊」? iOS ▪ In-App Purchase Programming Guide http://developer.apple. com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingS

    toreReceipts.html#//apple_ref/doc/uid/TP40008267-CH104-SW3 Android ▪ Purchase Status API https://developer.android.com/google/play/billing/gp-purchase-status-api.html#overview RTFM (Read The Fxxking Manual)
  4. 接受App傳來的資訊 驗證iOS的IAP需要用到哪些資訊? ▪ 應該要問問你的iOS developer ▪ 長的像這個樣子... ewoJInNpZ25hdHVyZSIgPSAiQXJSdHZLMn YzdzkzSUxBVzJEUnhGSnNZQTVSR25Wa2J PVHJEVUdEdlpsM2lVOThBUDJla1haNnh1O

    HVqaTBYeUpDSzNUME1yZUwyb1NmWlY3Y no4aFV3SWFHOThzWHhyeUpTaWhMS09XZ 2tkSXphY3JLTFZRbVZUMG1jVFdRRmhWK2 UxejZHSXFjSURGY3lTWDBmVlhYaVZocFZp YWlDT3REZ3FnRWk4MjM1...(略)... U0FBQURWekNDQTFNd2dnSTdvQU1DQVF JQ0NHVVVrVTNaV0FTMU1BMEdDU3F SKPaymentTransaction.transactionReceipt (base64 encoded)
  5. 接受App傳來的資訊 Native App應該要傳的資訊 ▪ receipt ▪ transaction ▪ user ▪

    sku (stock keeping unit = item + amount + unit price) ▪ store ▪ purchase info(price/currency/amount) ▪ device info(app version/platform/os/os version) ewoJInNpZ25hdHVyZSIgPSAiQXJSdHZLMn YzdzkzSUxBVzJEUnhGSnNZQTVSR25Wa2J PVHJEVUdEdlpsM2lVOThBUDJla1haNnh1O HVqaTBYeUpDSzNUME1yZUwyb1NmWlY3Y no4aFV3SWFHOThzWHhyeUpTaWhMS09XZ 2tkSXphY3JLTFZRbVZUMG1jVFdRRmhWK2 UxejZHSXFjSURGY3lTWDBmVlhYaVZocFZp YWlDT3REZ3FnRWk4MjM1...(略)... U0FBQURWekNDQTFNd2dnSTdvQU1DQVF JQ0NHVVVrVTNaV0FTMU1BMEdDU3F 1000000059372058 Account/Pasword SKPaymentTransaction.transactionIdentifier SKPaymentTransaction.transactionReceipt (base64 encoded)
  6. 接受App傳來的資訊 設計HTTP API ▪ 符合RESTful的原則 => POST ▪ /api/v1/purchase namespace

    :api do namespace :v1 do resources :purchase, controller: :iaps_controller, only: :create end end class Api::V1::IapsController < ApplicationController::Base def create #... end end config/route.rb app/controllers/api/v1/iaps_controller.rb
  7. 設計HTTP API ▪ 定義如何傳遞參數 Body { "iap" : { "store"

    : "aps", "receipt" : "ewoJInNpZ25hd...", "transaction" : "1000000059372058", "pinfo" : "price=199,currency=USD,amount=1", "dinfo" : "appver=1.0.0.0,platform=iPad,os=iOS,osver=6.1.1", "sku" : "ir4exu3b1" } } 接受App傳來的資訊 URL SITE_ADDR/api/v1/purchase Verb POST Controller#Method Api::V1::IapsController#create Basic-Auth (required) Accept-Language (required) Content-Type application/json
  8. 資料驗證 目的 ▪ 將明顯有問題的IAP排除,減少三方驗證的次數 要做什麼檢查? ▪ 傳入參數是否正確 ▪ 排除JB格式的receipt •

    惡名昭彰的com.urus.iap.xxxxxxxx ▪ 重複性驗證 • 用別人買過的receipt假裝是自己買的 ▪ sku驗證 • 用訂閱一個月的receipt假裝訂閱一年的
  9. 三方驗證(TPV) 我怎麼知道「要準備傳給Store哪種格式」、「Store 會回傳哪些資料」? iOS ▪ In-App Purchase Programming Guide http://developer.apple.

    com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingS toreReceipts.html#//apple_ref/doc/uid/TP40008267-CH104-SW3 RTFMA (Read The Fxxking Manual Again)
  10. 三方驗證(TPV) 一個iOS Subscription驗證成功回傳的結果 receipt: original_purchase_date_pst: "2013-08-28 13:32:49 America/Los_Angeles" unique_identifier: 0141e93bf3f3974e4375d8e078ab3872f5a84bd2

    original_transaction_id: "210000094738205" bvrs: 1.0.0.0 app_item_id: "382537495" transaction_id: "210000094738205" quantity: "1" unique_vendor_identifier: 461E36C-A382-ED35-50DA-DB86A5D32E84 product_id: com.your.product.itemcode item_id: "51713057" version_external_identifier: "10204710" bid: com.your.app.identity purchase_date_ms: "1377721969488" purchase_date: "2013-08-28 20:32:49 Etc/GMT" purchase_date_pst: "2013-08-28 13:32:49 America/Los_Angeles" original_purchase_date: "2013-08-28 20:32:49 Etc/GMT" original_purchase_date_ms: "1377721969488" status: 0
  11. 記錄交易內容 怎麼儲存這些資訊 id name 1 coin items id item_id 3

    1 skus id name 24 A coin package with 100 coins inside. skucode ir4exu3b1 price 199 amount 100 sku_id 3 user_id 19 store aps receipt ewoJInNpZ25hdHVyZSIg...(略)...EdDU3F transaction_val 100000005849368 pinfo price=11900,currency=TWD,amount=2 error_code 0 device_info appver=1.0.0,platform=ipad,os=iOS,osver=6.0.1 purchased_at 2013-08-02 18:01:53 purchases cancelled_at NULL created_at 2013-08-02 17:58:40 updated_at 2013-08-02 17:58:40 expires_at NULL
  12. 回傳結果 驗證成功 ▪ 一筆新的成功交易 => 更新資料並回傳成功 ▪ 重複的request => 不更新資料但也回傳成功

    驗證失敗 ▪ 參數有問題 => 直接回傳錯誤 ▪ 交易失敗或是異常 => 回傳error code與error message 重試 ▪ Store連線Timeout ▪ Store回傳特殊的error ▪ 發生internal exception
  13. 回傳結果 Status HTTP status code Response Body success 200 {

    "status" : 0 } duplicated 200 { "status" : 0 } invalid_request 422 failed 200 { "status" : 1, "code" : 21002, "msg" : "The data in the receipt-data property was malformed." } retry 200 { "status" : 2 } exception => retry 500
  14. 有code有真相 ▪ Model • Sku < ActiveRecord::Base • InAppPurchase <

    ActiveRecord::Base • FailedPurchase < ActiveRecord::Base ▪ Controller • IapsController < ApplicationController::Base ▪ File • config/application.yml
  15. 有code有真相 ▪ Module • IapHandler • IapStore • AppError ▪

    Class • IapStore::Base • IapStore::AppStore < IapStore::Base • IapStore::GooglePlay < IapStore::Base • AppError::Base • AppError::IapError < AppError::Base • AppError::IapAppStoreError < AppError::IapError
  16. 沒有什麼是困難簡單的 ▪ 取消訂閱(Cancel) 退款(Refund) 再訂閱(Re-Subscription) ▪ 多重訂閱(Multiple Subscription) ▪ 交易糾紛

    • 使用者說他買了,可是Server沒收到記錄? • 請洽客服 ▪ 一個頭三個大的finance report
  17. 處理 Auto-Renewable Subscription ▪ 一個schedule daemon定期去檢查快過期的 subscription ▪ 忽略App傳來的auto-renew request

    • 如何知道是同一筆的subscription的transcation ▪ 有一點差異的驗證資料 ▪ 只有續訂與取消訂閱,其它的情況都要重試 ▪ 檢查期間的buffer time,讓服務不中斷 ▪ 同步store訂閱的時間計算
  18. API實作技巧 ▪ API的特性 • 量大,response要快,回傳結果簡單,沒有session • 用rails做API server,你瘋了嗎??? ▪ API版本

    • Native App與Web App最大的差別 • /api/v1/purchase ▪ requet回傳結果的設計 ▪ 將API server與web server切開 ▪ API加速技巧 • 使用ActionController::Metal取代ActionController:: Base • 不使用View
  19. 三方驗證(TPV) 一個OSX Subscription驗證成功回傳的結果 status: 0 environment: Production receipt: receipt_type: ProductionReceipt

    adam_id: 5628xxxxx bundle_id: com.your.osx.app.identity application_version: 1.0.0.0 download_id: 320056xxxxxxxx request_date: "2013-09-05 12:01:25 Etc/GMT" request_date_ms: "13783xxxxxxxx" request_date_pst: "2013-09-05 05:01:25 America/Los_Angeles" in_app: - quantity: "1" product_id: com.your.osx.itemcode transaction_id: "1200000xxxxxxxx" original_transaction_id: "1200000xxxxxxxx" purchase_date: "2013-09-04 21:50:26 Etc/GMT" purchase_date_ms: "13783xxxxxxxx" purchase_date_pst: "2013-09-04 14:50:26 America/Los_Angeles" original_purchase_date: "2013-09-04 21:50:26 Etc/GMT" original_purchase_date_ms: "13783xxxxxxxx" original_purchase_date_pst: "2013-09-04 14:50:26 America/Los_Angeles"