Firefox Marketplace:驗證收據

作者:
瀏覽:491

如果你開發的是付費 App,就應該檢查消費者的收據是否有效。如果完全不檢查,則可能會有消費者購買 App 之後立刻退款,就變成能免費取得 App 了;或可能直接從你的網站參照 manifest 檔案就安裝了 App。如果開發者要建構收據驗證機制,可參閱本文提供的程式碼與作業流程。

注意:你會在「應用程式管理員 (App Manager)」看到「manifest」中文翻譯為「安裝資訊檔」。

收據 (Receipt) 即為消費者的 App 購買證明。收據將經由付款處理機制 (由消費者完成的交易) 產生確認資料 (Affirmation),以取得特定的數位產品。在消費者付費購買 Firefox Marketplace 上的 App 之後,收據就隨即傳送到消費者的裝置之中。位於消費者裝置上的收據,將用在 mozApps.install() 函式的第二組參數之上。Firefox Marketplace 將使用該筆收據資料,進而呼叫 install() 以完成 App 的安裝。

Firefox Marketplace:驗證收據

驗證收據的時機

開發者必須決定 App 該何時驗證收據。一般都是在消費者啟動 App 時開始驗證。如果是屬於長時間執行 App,則可以定時/定期進行驗證。例如影片串流 App 就可以每隔 20 分鐘檢查收據 1 次。

另請注意,如果消費者為離線狀態,App 也就無法驗證收據。開發者可決定 App 在離線時所進行的作業。為了避免打擾某些消費者,開發者可停止強制的收據驗證作業 (消費者可能進入隧道而暫時離線),只要等消費者上線時再次檢查即可。

如何驗證收據

最簡單就是使用 Firefox Marketplace 的驗證服務即可。如果你的 App 屬於「HTML-only」,也就是伺服器只會提供靜態檔案,則可使用 Mozilla 的「receiptverifier」JavaScript 函式庫。此函式庫基本上只會將 receiptverifier.js 指令碼加入 App 之中,並使用 verifyReceipts() 函式。可參閱上述連結以進一步了解。

收據內容

Open Web App 所使用的收據,均為可攜式、可驗證的「Token」購買證明,即所謂 JSON Web Token (JWT) 的數位簽署 JSON 資料架構,且此格式可讓所有用戶端與伺服器讀取。許多程式語言均提供 JWT 函式庫。

應接受的收據

收據就是付款的證明,但 App 開發者可決定自己想要的收據類型。以下是你該檢查的要項:

  • 收據來自於售出 App 的商店。請檢查自己清單中的 iss 欄位。
  • 自己 App 的專屬收據。如果是架設/托管式 (Hosted) App,可檢查 product URL 欄位是否正確。如果是封裝式 (Packaged) App,可檢查 product storeData 是否正確,直到 bug 867265 解決為止。除非已發出收據,否則 storeData 均為未知值,且發出收據之後將不再變動。
  • 驗證作業的網址是位於商店的網域或子網域之下。可檢查 verify 的網址是否為 iss 欄位的子網域。
  • 收據真正用於購買活動,而非測試用收據。請檢查 typ 欄位。

receipt verifier 函式庫可進行其中數項檢查。

測試用收據

在開發期間,Firefox Marketplace 即可協助發出測試用收據,以供完整測試 App 的相關功能。此種收據將具備「test-receipt」的 typ。且 App 只會在開發期間接收這類收據,一旦上架之後就停止接收;否則消費者可略過 App 銷售程序,直接使用測試用收據。

receipt verifier 函式庫預設不會接收 test-receipts

收據驗證

在沒有 JWT 函式庫的情況下,開發者也能在收據的 verify 欄位中,找到驗證服務的對應網址,並將收據傳送給驗證服務。各個 App 均具備不同的 Firefox Marketplace 驗證服務網址。

下列範例程式碼可於收據中顯示 verify 網址。該程式碼將用於 Firefox 的「網頁主控台 (Web console)」開發者工具。

var request = navigator.mozApps.getSelf();
request.onsuccess = function() {
  // Get the app's receipt and decode it
  console.log(atob(request.result.receipts[0].split('~')[1].split('.')[1])); 
};

為了取得 verify 網址,此範例將近行下列作業:

  • 針對由 mozApps.getSelf() (對目前 App 的參照) 所回傳的物件,將之儲存於 request 變數中。
  • 如果請求成功,則會檢索 App 的第一筆收據,且將切割由 JWT 送進的值,以取得包含收據的實際部位。
  • 透過 JavaScript 的 Window.atob 函式,而解碼 Base64-encoded 的收據。

接著是上述程式碼結果的完整範例。此即為扣除 JWT 部分的完整收據。

{
  "product": {
    "url": "http://example.com",
    "storedata": "id=111111"
  },
  "iss": "https://marketplace.mozilla.org",
  "verify": "https://receiptcheck.marketplace.mozilla.org/verify/111111", // The verify URL
  "detail": "https://marketplace.mozilla.org/en-US/purchases/111111",
  "reissue": "https://marketplace.mozilla.org/en-US/app/example/purchase/reissue",
  "user": {
    "type": "directed-identifier",
    "value": "1234-abcd99ef-a123-456b-bbbb-cccc11112222"
  },
  "exp": 1353028900,
  "iat": 1337304100,
  "typ": "purchase-receipt",
  "nbf": 1337304100
}

在開發者取得 verify 網址之後,就可透過 POST 函式,在訊息主體之內傳送完整的 JWT。驗證服務的回應即如上方所述。下列程式碼片段 (snippet),將從上列範例中取得 App 第一筆收據的完整 JWT。

request.result.receipts[0]

請注意,上述程式碼並不會處理 JWT 的加密部分。如果你要透過 Marketplace 驗證收據,則收據將檢查本身的加密簽章。

注意:可在 Kumar McMillan 提供的 Private Yacht 範例中,找到其他更高擴充性的收據驗證範例。

App 盜版問題

即使你驗證了自己付費 App 的收據,還是可能有人繞過收據機制而盜用 App。上列的收據驗證函式並無法避免此問題。

如果想要更好的防盜版機制,就必須設定代理伺服器,將之作為 App 與 Firefox Marketplace 之間的媒介。代理伺服器可檢查收據、IP 位址,還有更多物件。如果單一收據來自於不同的 IP 位址,且能一樣執行正確動作,則伺服器就可進行類似通知的作業。如果是大型、複雜、使用伺服器處理功能的 App,就能達到更適當、更正確的設定。

此 Python 程式碼仍是開發中的專案,可提供某些代理伺服器的靈感。Django Receipts 則是測試用的代理伺服器,可驗證收據。開發者最好不要直接將之作為正式運行的代理伺服器,但可進行測試以了解相關機制。另可參閱更多資訊,讓自己了解收據驗證作業。

收據欄位

收據應包含下列欄位:

typ
可供識別收據類型的字串,必為以下之一:
  • purchase-receipt ─ 交易完成之後隨即發出的收據。這類收據應隨時能由 App 接收。
  • developer-receipt ─ 由 App 開發者所發出的收據。一般是開發者交由自己使用的 App 商店所發出。這類收據有效期較短。
  • reveiwer-receipt ─ 由 App 審查者所發出的收據。一般是 App 審查者透過其所位於的商店發出。這類收據只需要在審查期間接收即可,有效期較短。
  • test-receipt ─ 在開發期間用以測試 App 所發出的收據。只要是開發期間以外,均不應該接收這類收據,有效期較短。
product
JSON 物件在識別產品時,包含收據所囊括的範圍,以及任何特定商店的資料。包含下列欄位:
  • url ─ 代表該網址的根網域 (root of a domain),且沒有最後的斜線 (例如「https://someapp.com」)。一般這樣就代表了 Web App。如果是以根網域開頭的其他網址,則代表「App 內購買」。只要開發者或收據開立者覺得方便,則可使用各種路徑規則 (Path scheme)。
  • storedata ─ 此字串為 App 所獨有,將提供給收據驗證器 (Verifier) 所用。
user
針對完成購買作業的消費者,此 JSON 物件包含了使用者 ID,並包含下列欄位:
  • type ─ 此字串內有「directed-identifier」值。
  • value ─ 此字串即為消費者的專屬 ID。消費者每次購買 App,都會擁有不同的 ID。
iss
發出收據的商店,其所屬之網域。
nbf
完成購買程序之後,顯示「Not-before」的時間戳記。時間戳記是從 1970-01-01T00:00:00Z (UTC, RFC 3339) 開始的秒數。
iat
發出收據之後,顯示「Issued-at」的時間戳記。此時間戳記的格式如同 nbf。可透過此數值決定收據的存在時間。
exp
(選填) 代表收據過期的時間戳記。此時間戳記的格式如同 nbf
detail
(選填) 網址包含額外人、機均可讀取的購買細節。如果另提供購買行為的交易記錄或退款功能,則本頁亦應包含相關函式。
verify
(選填) 由經過授權的 App 使用此網址,以驗證收據。另請注意,Firefox Marketplace 一定會為 App 提供此欄位。如果開發者想自己建立 App 的商城,就可能不需使用此欄位。
reissue
(選填) 網址可重新發出新收據。

 

 

Mozilla 開發者社群網站 (MDN) 原文連結:Validating a receipt

你也可參閱中文版《驗證收據》,我們將根據原文而持續更新內容。另可參閱 MDN 上的更多 Firefox OS 或 Marketplace 相關文章。