サーバーサイドの確認コールバックは、クエリ パラメータを含む URL リクエスト Google によって拡張され、Google から外部システムに リワード広告やチャット メッセージなどの操作で報酬を リワード インタースティシャル広告。リワード SSV(サーバー側の検証)コールバック クライアントサイドのコールバックのなりすましに対する保護を強化します。 特典を提供しています
このガイドでは、 Tink Java アプリ(サードパーティ) この暗号ライブラリを使用して、コールバックのクエリ パラメータが確実に 判断します このガイドでは Tink を使用していますが、 サポートされているサードパーティ ライブラリを ECDSA。 また、testing ツールを使用します。
こちらの完全に機能している 例 使用します。
前提条件
リワード広告を モバイルアプリで v3.12.0 以降の Google Mobile Ads Unity プラグイン
サーバーサイドでのリワード獲得を有効化 確認する必要があります。
Tink Java Apps ライブラリの RewardAdsVerifier を使用する
Tink Java Apps GitHub リポジトリ
含まれる
RewardedAdsVerifier
ヘルパークラスを追加し、リワード SSV コールバックの検証に必要なコードを削減しています。
このクラスを使用すると、次のコードでコールバック URL を確認できます。
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
例外が発生せずに verify()
メソッドが実行されると、
URL は正常に確認されました。ユーザーへの特典
では、ユーザーに報酬を付与するタイミングに関するベスト プラクティスを詳しく説明しています。1 つの
リワード SSV コールバックを検証するためにこのクラスが実行するステップの詳細
詳しくは、Google 広告利用規約の
SSV セクションがあります。
SSV コールバック パラメータ
サーバーサイドの検証コールバックには、 リワード広告のインタラクションです。パラメータ名、説明、値の例は、 下の一覧をご覧ください。パラメータはアルファベット順に送信されます。
パラメータ名 | 説明 | 値の例 |
---|---|---|
ad_network | この広告を配信した広告ソースの ID。広告のソース ID 値に対応する名前のリストが、広告 ソース識別子セクションを参照してください。 | 1953547073528090325 |
ad_unit | リワード広告のリクエストに使用された AdMob 広告ユニット ID。 | 2747237135 |
key_id | SSV コールバックの検証に使用するキー。この値は、公開鍵と AdMob キーサーバーから取得されます。 | 1234567890 |
reward_amount | 広告ユニットの設定で指定された報酬額。 | 5 |
reward_item | 広告ユニットの設定で指定された報酬アイテム。 | コイン |
署名 | AdMob が生成した SSV コールバックの署名。 | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
タイムスタンプ | ユーザーが報酬を受け取ったときのエポックタイムのタイムスタンプ(ミリ秒単位)。 | 1507770365237823 |
transaction_id | AdMob によって生成された特典付与イベントごとに、16 進数でエンコードされた一意の ID。 | 18fa792de1bca816048293fc71035638 |
user_id | 提供元: ユーザー ID
SetUserId を使用します。
アプリからユーザー ID が提供されていない場合、このクエリ パラメータは SSV コールバックに含まれます。 |
1234567 |
広告ソースの識別子
広告ソースの名前と ID
Ad source name | Ad source ID |
---|---|
Aarki (bidding) | 5240798063227064260 |
Ad Generation (bidding) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (non-SDK) (bidding) | 4600416542059544716 |
AdColony (bidding) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
AdMob Network | 5450213213286189855 |
AdMob Network Waterfall | 1215381445328257950 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
Applovin | 1063618907739174004 |
Applovin (bidding) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform (bidding) | 6432849193975106527 |
CrossChannel (MdotM) | 9372067028804390441 |
Custom Event | 18351550913290782395 |
DT Exchange* * Prior to September 21, 2022, this network was called "Fyber Marketplace". | 2179455223494392917 |
EMX (bidding) | 8497809869790333482 |
Fluct (bidding) | 8419777862490735710 |
Flurry | 3376427960656545613 |
Fyber* * This ad source is used for historical reporting. | 4839637394546996422 |
i-mobile | 5208827440166355534 |
Improve Digital (bidding) | 159382223051638006 |
Index Exchange (bidding) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (bidding) | 6325663098072678541 |
InMobi Exchange (bidding) | 5264320421916134407 |
IronSource | 6925240245545091930 |
ironSource Ads (bidding) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
LINE Ads Network | 3025503711505004547 |
maio | 7505118203095108657 |
maio (bidding) | 1343336733822567166 |
Media.net (bidding) | 2127936450554446159 |
Mediated house ads | 6060308706800320801 |
Meta Audience Network* * Prior to June 6, 2022, this network was called "Facebook Audience Network". | 10568273599589928883 |
Meta Audience Network (bidding)* * Prior to June 6, 2022, this network was called "Facebook Audience Network (bidding)". | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral (bidding) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox (bidding) | 3086513548163922365 |
MoPub (deprecated) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen (bidding)* * Prior to May 1, 2024, this network was called "UnrulyX". | 2831998725945605450 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange (bidding) | 4873891452523427499 |
OpenX (bidding) | 4918705482605678398 |
Pangle | 4069896914521993236 |
Pangle (bidding) | 3525379893916449117 |
PubMatic (bidding) | 3841544486172445473 |
Reservation campaign | 7068401028668408324 |
RhythmOne (bidding) | 2831998725945605450 |
Rubicon (bidding) | 3993193775968767067 |
SK planet | 734341340207269415 |
Sharethrough (bidding) | 5247944089976324188 |
Smaato (bidding) | 3362360112145450544 |
Equativ (bidding)* * Prior to January 12, 2023, this network was called "Smart Adserver". | 5970199210771591442 |
Sonobi (bidding) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (bidding) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift (bidding) | 8332676245392738510 |
Unity Ads | 4970775877303683148 |
Unity Ads (bidding) | 7069338991535737586 |
Verizon Media | 7360851262951344112 |
Verve Group (bidding) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Liftoff Monetize* * Prior to January 30, 2023, this network was called "Vungle". | 1953547073528090325 |
Liftoff Monetize (bidding)* * Prior to January 30, 2023, this network was called "Vungle (bidding)". | 4692500501762622185 |
Yieldmo (bidding) | 4193081836471107579 |
YieldOne (bidding) | 3154533971590234104 |
Zucks | 5506531810221735863 |
ユーザーへの特典
決定する際には、ユーザー エクスペリエンスと報酬検証のバランスを取ることが重要 ユーザーに報酬を 与えるタイミングを決定しますサーバーサイドのコールバックは、 外部システムに到達しますそのため、推奨されるベスト プラクティスは、 クライアントサイドのコールバックを実行して、ユーザーに サーバーサイド コールバックの受信時に、すべてのリワードの検証を行う。この ユーザー エクスペリエンスを損なわないように、Google Cloud で付与される 。
ただし、報酬の有効性が重要なアプリケーション( アプリのゲーム内経済に影響を及ぼし、報酬の付与が遅れた場合、 確認されたサーバーサイドのコールバックを待つことが、 アプローチです
カスタムデータ
サーバー側の検証コールバックで追加データを必要とするアプリでは、
リワード広告のカスタムデータ機能リワード広告に設定されている文字列値
SSV コールバックの custom_data
クエリ パラメータに渡されます。「いいえ」の場合
カスタムデータ値が設定されている場合、custom_data
クエリ パラメータ値は
SSV コールバックに含まれます。
次のコードサンプルは、コマンドの後に SSV オプションを設定する方法を示しています。 リワード広告が読み込まれました。
private void LoadRewardedAd(string adUnitId)
{
// Send the request to load the ad.
AdRequest adRequest = new AdRequest();
RewardedAd.Load(adUnitId, adRequest, (RewardedAd rewardedAd, LoadAdError error) =>
{
// If the operation failed with a reason.
if (error != null)
{
Debug.LogError("Rewarded ad failed to load an ad with error : " + error);
return;
}
var options = new ServerSideVerificationOptions
.Builder()
.SetCustomData("SAMPLE_CUSTOM_DATA_STRING")
.Build()
rewardedAd.SetServerSideVerificationOptions(options);
});
}
カスタム報酬文字列を設定する場合は、表示する前に設定する必要があります。 表示されます。
リワード SSV の手動検証
リワードを検証するために RewardedAdsVerifier
クラスが実行するステップ
SSV の概要は以下のとおりです。用意されているコード スニペットは Java と Java で記述されていますが、
Tink のサードパーティ ライブラリを使用する場合は、この手順を
サポートしているサードパーティ ライブラリを使用して、任意の言語で
ECDSA。
公開鍵を取得する
リワード SSV コールバックを検証するには、AdMob から提供される公開鍵が必要です。
リワード SSV コールバックの検証に使用する公開鍵のリストは、 (AdMob キーから取得) できます。公開鍵のリストは、 は、次のような形式の JSON 表現として提供されます。
{
"keys": [
{
keyId: 1916455855,
pem: "-----BEGIN PUBLIC KEY-----\nMF...YTPcw==\n-----END PUBLIC KEY-----"
base64: "MFkwEwYHKoZIzj0CAQYI...ltS4nzc9yjmhgVQOlmSS6unqvN9t8sqajRTPcw=="
},
{
keyId: 3901585526,
pem: "-----BEGIN PUBLIC KEY-----\nMF...aDUsw==\n-----END PUBLIC KEY-----"
base64: "MFYwEAYHKoZIzj0CAQYF...4akdWbWDCUrMMGIV27/3/e7UuKSEonjGvaDUsw=="
},
],
}
公開鍵を取得するには、AdMob 鍵サーバーに接続して
できます。次のコードはこのタスクを実行し、
data
変数に対するキーの表現。
String url = ...;
NetHttpTransport httpTransport = new NetHttpTransport.Builder().build();
HttpRequest httpRequest =
httpTransport.createRequestFactory().buildGetRequest(new GenericUrl(url));
HttpResponse httpResponse = httpRequest.execute();
if (httpResponse.getStatusCode() != HttpStatusCodes.STATUS_CODE_OK) {
throw new IOException("Unexpected status code = " + httpResponse.getStatusCode());
}
String data;
InputStream contentStream = httpResponse.getContent();
try {
InputStreamReader reader = new InputStreamReader(contentStream, UTF_8);
data = readerToString(reader);
} finally {
contentStream.close();
}
公開鍵は定期的にローテーションされることに注意してください。その旨をメールで通知 表示されなくなります。公開鍵をキャッシュに保存している場合は、 鍵をローテーションしてください。
取得した公開鍵は、解析する必要があります。「
以下の parsePublicKeysJson
メソッドは、
key_id
値から公開鍵へのマッピングを作成します。
Tink ライブラリの ECPublicKey
オブジェクトとしてカプセル化されています。
private static Map<Integer, ECPublicKey> parsePublicKeysJson(String publicKeysJson)
throws GeneralSecurityException {
Map<Integer, ECPublicKey> publicKeys = new HashMap<>();
try {
JSONArray keys = new JSONObject(publicKeysJson).getJSONArray("keys");
for (int i = 0; i < keys.length(); i++) {
JSONObject key = keys.getJSONObject(i);
publicKeys.put(
key.getInt("keyId"),
EllipticCurves.getEcPublicKey(Base64.decode(key.getString("base64"))));
}
} catch (JSONException e) {
throw new GeneralSecurityException("failed to extract trusted signing public keys", e);
}
if (publicKeys.isEmpty()) {
throw new GeneralSecurityException("No trusted keys are available.");
}
return publicKeys;
}
検証するコンテンツを取得する
リワード SSV コールバックの最後の 2 つのクエリ パラメータは常に signature
である
key_id,
の順に並べます。残りのクエリ パラメータは、コンテンツ
あります。報酬のコールバックを
https://www.myserver.com/mypath
。以下のスニペットは、リワード広告スペースで
検証するコンテンツがハイライト表示された SSV コールバック。
https://www.myserver.com/path?ad_network=54...55&ad_unit=12345678&reward_amount=10&reward_item=coins ×tamp=150777823&transaction_id=12...DEF&user_id=1234567&signature=ME...Z1c&key_id=1268887
次のコードは、 UTF-8 バイト配列として指定します。
public static final String SIGNATURE_PARAM_NAME = "signature=";
...
URI uri;
try {
uri = new URI(rewardUrl);
} catch (URISyntaxException ex) {
throw new GeneralSecurityException(ex);
}
String queryString = uri.getQuery();
int i = queryString.indexOf(SIGNATURE_PARAM_NAME);
if (i == -1) {
throw new GeneralSecurityException("needs a signature query parameter");
}
byte[] queryParamContentData =
queryString
.substring(0, i - 1)
// i - 1 instead of i because of & in the query string
.getBytes(Charset.forName("UTF-8"));
コールバック URL から署名と key_id を取得する
前の手順の queryString
値を使用して、signature
を解析します。
次のように、コールバック URL から key_id
クエリ パラメータを渡します。
public static final String KEY_ID_PARAM_NAME = "key_id=";
...
String sigAndKeyId = queryString.substring(i);
i = sigAndKeyId.indexOf(KEY_ID_PARAM_NAME);
if (i == -1) {
throw new GeneralSecurityException("needs a key_id query parameter");
}
String sig =
sigAndKeyId.substring(
SIGNATURE_PARAM_NAME.length(), i - 1 /* i - 1 instead of i because of & */);
int keyId = Integer.valueOf(sigAndKeyId.substring(i + KEY_ID_PARAM_NAME.length()));
確認を行う
最後に、コールバック URL の内容を
あります。イベントタイプから返されたマッピングを
parsePublicKeysJson
メソッドを使用して、コールバックの key_id
パラメータを使用します。
URL を使用して、そのマッピングから公開鍵を取得します。次に、署名を
あります。これらのステップは、以下の verify
メソッドで示されます。
private void verify(final byte[] dataToVerify, int keyId, final byte[] signature)
throws GeneralSecurityException {
Map<Integer, ECPublicKey> publicKeys = parsePublicKeysJson();
if (publicKeys.containsKey(keyId)) {
foundKeyId = true;
ECPublicKey publicKey = publicKeys.get(keyId);
EcdsaVerifyJce verifier = new EcdsaVerifyJce(publicKey, HashType.SHA256, EcdsaEncoding.DER);
verifier.verify(signature, dataToVerify);
} else {
throw new GeneralSecurityException("cannot find verifying key with key ID: " + keyId);
}
}
例外をスローせずにメソッドが実行された場合、 確認されました。
よくある質問
- AdMob 鍵サーバーから提供された公開鍵をキャッシュに保存できますか?
- AdMob キーから提供された公開鍵をキャッシュに保存することをおすすめします SSV の検証に必要なオペレーションの数を削減できる 使用できます。ただし、公開鍵は定期的にローテーションされるため、 24 時間以上キャッシュされないようにします。
- AdMob 鍵サーバーが提供する公開鍵は、どのくらいの頻度でローテーションされますか?
- AdMob 鍵サーバーによって提供される公開鍵は、変数 できます。SSV コールバックの検証を今後も引き続き 公開鍵を 24 時間以上キャッシュしてはいけません。
- サーバーにアクセスできない場合はどうなりますか?
- SSV に対して
HTTP 200 OK
成功ステータス レスポンス コードが返される 使用できます。サーバーにアクセスできない場合や、想定どおりの応答が得られない場合 リクエストが送信されると、Google は SSV コールバックの送信を 5 回まで再試行します。 1 秒間隔です。 - SSV コールバックの送信元が Google であることを確認するにはどうすればよいですか?
- リバース DNS ルックアップを使用して、SSV コールバックの送信元が Google であることを確認する。