その他
    ホーム 職種別 エンジニア 課金の実装時にサーバー側は何をやるのか
    課金の実装時にサーバー側は何をやるのか
     

    課金の実装時にサーバー側は何をやるのか

    今回は、アピリッツの知識共有サイト「ナレッジベース」で公開されている内容をアピスピでも紹介します。
    エンジニアとして活躍されている鳴澤秀夫さんの記事です。
    是非最後まで読んでください!(初版:2021年12月22日)

    え!!一切未経験なのに課金実装を!?

    エンジニア兼デスクにフィギュアを置いてモチベを上げる者の鳴澤です。

    執筆時現在はPHP/Laravelを使用してUnity製ソシャゲ(パズルゲーム)のバックエンドをやっています。

    今回はその案件での体験談的なメモを残します。
    注) 今回はあくまで「何をやるのかのメモ」程度ですので、詳細な手順やソースコードなどは割愛します。

    サーバー側は主に”不正チェック”をする!

    まず、課金処理がどのようなフローになっているかを以下のシーケンス図にまとめてみました。

    サーバー側はこの中でも4〜7の工程が大事になってきます。

    ※ 課金APIとは、GooglePlayStoreやiTunesStoreといった課金プラットフォームが用意したAPIの意味です

    これだけ見るとナンノコッチャだと思うので、以下で軽く解説してみます。

    工程1〜3 アプリ(クライアント)側の処理 

    ソシャゲで石を買おうとした時、AndroidやiOSのUIで「課金しますか?」みたいな確認画面が出ると思います。
    そこで購入処理を行うと、アプリから課金APIへ購入処理のリクエストが送信されます。

    正常に決済処理がされたら「レシート」データが返ってきます。(これが後に大事になります)

    なんと、この時点で課金処理そのものは完成しているのです!

    しかし大抵のソシャゲはアプリ側の処理だけでは終わらず、サーバー側と連携してアイテム付与などを行いますよね?

    なのでサーバー側でAPIを実装し、アプリ側から叩いてもらいましょう。
    その際、先程課金APIから返ってきた「レシート」をリクエストに含んでもらいます。

    “レシート”とは何か

    課金APIに決済処理をリクエストした際の取引の詳細がまとまったJSONデータです。
    プラットフォームによってはbase64で暗号化された状態で返ってきたりします。

    決済をして返ってくるデータなので正にレシートと言ったところですね。

    このレシートには主に

    • 購入日時(エポック秒)
    • 商品のID(ストア側で設定ができる)
    • 取引ID(トランザクション番号とも。アプリ単位で一意な文字列が入る)

    といった、誰がいつ何を買ったかを一発で特定可能なデータが入っています。
    この”一意なデータ”であることが、今後のチェック処理で大事になってきます。

    工程4〜5 レシート検証

    アプリ側からサーバー側へは、決済時にストアから返ってきたレシートをリクエストに含めてAPIを叩きます。
    サーバー側は、このレシートがあること(買った事実があること)を確認して石やアイテムを付与するんですね。

    そこで悪い人は考えました。
    偽装レシートを使ってサーバー側APIを叩きまくったら、大量に石をゲットできるんじゃね!?」

    こういう悪人に”エラー表示”という正義の鉄槌を下すために実装するのが「レシート検証」です。

    要するに不正防止策ですね。

    実装方針

    実はアプリ側に返ってきた物とは別に、ストア側にもレシートが保存されています。
    ストア側の課金APIにレシートを請求することで、アプリから送られてきたレシートが偽装された物でないかチェックが可能なのです。

    存在しないレシートだった場合は課金APIからエラーが返ってきますので、エラーか否かでチェックすれば間違いないので簡単ですね。

    GooglePlayStoreではレシートを取得するためだけにOAuth認証をしてアクセストークンを取得する必要があるのですが、これが結構面倒でした。
    この辺に関しては別の機会にまとめられたらと思います。

    工程6〜7 重複チェック

    ここまでの実装で、偽装レシートを用いた不正は防ぐことができましたね。

    そこで悪い人は考えました。
    過去のレシートを使って偽装じゃないと認識させれば、大量に石をゲットできるんじゃね!?」

    こういう悪人を”わからせる”ために実装するのが「重複チェック」です。

    アプリ側の問題で同じリクエストが2連続で飛んでくるケースもあるため、不正対策だけでなくバグ防止の観点でも大事な部分です。

    実装方針

    先程も軽く触れましたが、レシートには 「購入日時(エポック秒)」や「取引ID」といった組み合わせると完全に一意となるデータが色々入っています。

    これらをゲーム側のDBに保存しておき、全く同じレコードが存在しないかを検索するのが一般的な手法です。

    工程8 DBに保存 

    こうして正常なレシートであることを証明できたので、DBの更新をします。

    売り物のアイテムをユーザーDBに付与して保存する他、先程の重複検証で用いた”一意なデータ”も別途テーブルに保存します。

    ここでレシートの値を保存することで、次回以降の重複チェックで比較対象として使われていくことになります。

    他にも何かやるの?

    • 各ストアにテスト用の商品を登録(面倒)
    • 各ストアにテストプレイを許可するアカウントを登録(面倒)
    • OAuth認証やトークン周りの実装(面倒)
    • サービス用のアカウントを作成し、課金APIのアクセス権限を付与(面倒)
    • 今回の記事は通常課金のケースだけど、別途月額課金にも対応するよう実装(超面倒)

    と、やることが結構多くて実装頑張ったなと自分でも思います。
    この辺は今後少しずつ紹介できたらなと思っています。


    鳴澤さんありがとうございました!

    アピリッツでは自分が得た情報や技術を積極的に共有し、それらを吸収しながら各々のスキルアップを目指しています。
    アピリッツに少しでも興味を持った方、エントリーお待ちしております!

    エントリーはこちらをチェック→〈https://recruit.appirits.com/

    記事を共有