การเรียกกลับการยืนยันฝั่งเซิร์ฟเวอร์คือคำขอ URL ที่มีพารามิเตอร์การค้นหา ซึ่ง Google ขยายความและส่งไปยังระบบภายนอกเพื่อ แจ้งให้ทราบว่าผู้ใช้ควรได้รับรางวัลสำหรับการโต้ตอบกับโฆษณาวิดีโอที่มีการให้รางวัลหรือ โฆษณาคั่นระหว่างหน้าที่มีการให้รางวัล การเรียกกลับ SSV (การยืนยันฝั่งเซิร์ฟเวอร์) ที่มีรางวัล จะช่วยเพิ่มการป้องกันอีกชั้นจากการปลอมแปลงการเรียกกลับทางฝั่งไคลเอ็นต์ เพื่อมอบรางวัลให้แก่ผู้ใช้
คู่มือนี้แสดงวิธียืนยันการเรียกกลับ SSV ที่มีรางวัลโดยใช้ไลบรารี การเข้ารหัสของบุคคลที่สาม Tink Java Apps เพื่อให้มั่นใจว่าพารามิเตอร์การค้นหาในการเรียกกลับเป็นค่าที่ถูกต้อง แม้ว่าเราจะใช้ Tink เพื่อวัตถุประสงค์ของคู่มือนี้ แต่คุณก็มีตัวเลือกในการ ใช้ไลบรารีของบุคคลที่สามที่รองรับ ECDSA นอกจากนี้ คุณยังทดสอบเซิร์ฟเวอร์ด้วยเครื่องมือ ทดสอบใน UI ของ AdMob ได้ด้วย
ข้อกำหนดเบื้องต้น
- เปิดใช้การยืนยันฝั่งเซิร์ฟเวอร์ที่มีการให้รางวัลในหน่วยโฆษณา
ใช้ RewardedAdsVerifier จากไลบรารี Tink Java Apps
ที่เก็บ 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 ของการเรียกกลับสำเร็จแล้ว ส่วนการให้รางวัลแก่ผู้ใช้
จะอธิบายแนวทางปฏิบัติแนะนำเกี่ยวกับเวลาที่ควรให้รางวัลแก่ผู้ใช้ หากต้องการดูรายละเอียดขั้นตอนที่คลาสนี้ดำเนินการเพื่อยืนยันการเรียกกลับ SSV ที่มีรางวัล
คุณสามารถอ่านส่วนการยืนยัน SSV ที่มีรางวัลด้วยตนเอง
พารามิเตอร์การเรียกกลับ SSV
การเรียกกลับการยืนยันฝั่งเซิร์ฟเวอร์มีพารามิเตอร์การค้นหาที่อธิบาย การโต้ตอบกับโฆษณาที่มีการให้รางวัล ชื่อ คำอธิบาย และค่าตัวอย่างของพารามิเตอร์ แสดงอยู่ด้านล่าง ระบบจะส่งพารามิเตอร์ตามลำดับตัวอักษร
| ชื่อพารามิเตอร์ | คำอธิบาย | ค่าตัวอย่าง |
|---|---|---|
| ad_network | ตัวระบุแหล่งที่มาของโฆษณาสําหรับแหล่งที่มาของโฆษณาที่แสดงโฆษณานี้ ชื่อแหล่งที่มาของโฆษณา ที่สอดคล้องกับค่ารหัสจะแสดงอยู่ในส่วนตัวระบุแหล่งที่มาของโฆษณา | 1953547073528090325 |
| ad_unit | รหัสหน่วยโฆษณา AdMob ที่ใช้ขอโฆษณาที่มีการให้รางวัล | 2747237135 |
| custom_data | สตริงข้อมูลที่กำหนดเองตามที่
customData ระบุ
หากแอปไม่ได้ระบุสตริงข้อมูลที่กําหนดเอง พารามิเตอร์การค้นหานี้ จะไม่มีค่าในการเรียกกลับ SSV |
SAMPLE_CUSTOM_DATA_STRING |
| key_id | คีย์ที่จะใช้เพื่อยืนยันการเรียกกลับ SSV ค่านี้จะแมปกับคีย์สาธารณะ ที่ได้รับจากเซิร์ฟเวอร์คีย์ของ AdMob | 1234567890 |
| reward_amount | จำนวนรางวัลตามที่ระบุในการตั้งค่าหน่วยโฆษณา | 5 |
| reward_item | ไอเทมรางวัลตามที่ระบุในการตั้งค่าหน่วยโฆษณา | เหรียญ |
| ลายเซ็น | ลายเซ็นสำหรับการเรียกกลับ SSV ที่ AdMob สร้างขึ้น | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
| การประทับเวลา | การประทับเวลาเมื่อผู้ใช้ได้รับรางวัลเป็นเวลา Epoch ในหน่วยมิลลิวินาที | 1507770365237823 |
| transaction_id | ตัวระบุที่ไม่ซ้ำกันที่เข้ารหัสฐาน 16 สำหรับเหตุการณ์การให้รางวัลแต่ละรายการที่ AdMob สร้างขึ้น | 18fa792de1bca816048293fc71035638 |
| user_id | ตัวระบุผู้ใช้ตามที่
userId ระบุ
หากแอปไม่ได้ระบุตัวระบุผู้ใช้ พารามิเตอร์การค้นหานี้จะไม่ อยู่ในการเรียกกลับ SSV |
1234567 |
ตัวระบุแหล่งที่มาของโฆษณา
ชื่อและรหัสแหล่งที่มาของโฆษณา
| ชื่อแหล่งที่มาของโฆษณา | รหัสแหล่งที่มาของโฆษณา |
|---|---|
| การสร้างโฆษณา (การเสนอราคา) | 1477265452970951479 |
| AdColony | 15586990674969969776 |
| AdColony (การเสนอราคา) | 6895345910719072481 |
| AdFalcon | 3528208921554210682 |
| เครือข่าย AdMob | 5450213213286189855 |
| การแสดงโฆษณาตามลำดับขั้นของเครือข่าย AdMob | 1215381445328257950 |
| Applovin | 1063618907739174004 |
| Applovin (การเสนอราคา) | 1328079684332308356 |
| Chartboost | 2873236629771172317 |
| Chocolate Platform (การเสนอราคา) | 6432849193975106527 |
| เหตุการณ์ที่กำหนดเอง | 18351550913290782395 |
| DT Exchange* * ก่อนวันที่ 21 กันยายน 2022 เครือข่ายนี้มีชื่อว่า "Fyber Marketplace" | 2179455223494392917 |
| Equativ (การเสนอราคา)* * ก่อนวันที่ 12 มกราคม 2023 เครือข่ายนี้มีชื่อว่า "Smart Adserver" | 5970199210771591442 |
| Fluct (การเสนอราคา) | 8419777862490735710 |
| Flurry | 3376427960656545613 |
| Fyber* * แหล่งที่มาของโฆษณานี้ใช้สําหรับการรายงานข้อมูลย้อนหลัง | 4839637394546996422 |
| i-mobile | 5208827440166355534 |
| Improve Digital (การเสนอราคา) | 159382223051638006 |
| Index Exchange (การเสนอราคา) | 4100650709078789802 |
| InMobi | 7681903010231960328 |
| InMobi (การเสนอราคา) | 6325663098072678541 |
| InMobi Exchange (การเสนอราคา) | 5264320421916134407 |
| IronSource | 6925240245545091930 |
| ironSource Ads (การเสนอราคา) | 1643326773739866623 |
| Leadbolt | 2899150749497968595 |
| Liftoff Monetize* * ก่อนวันที่ 30 มกราคม 2023 เครือข่ายนี้มีชื่อว่า "Vungle" | 1953547073528090325 |
| Liftoff Monetize (การเสนอราคา)* * ก่อนวันที่ 30 มกราคม 2023 เครือข่ายนี้มีชื่อว่า "Vungle (การเสนอราคา)" | 4692500501762622185 |
| LG U+AD | 18298738678491729107 |
| LINE Ads Network | 3025503711505004547 |
| Magnite DV+ (การเสนอราคา) | 3993193775968767067 |
| maio | 7505118203095108657 |
| maio (การเสนอราคา) | 1343336733822567166 |
| Media.net (การเสนอราคา) | 2127936450554446159 |
| โฆษณาเฮาส์แอ็ดที่ใช้สื่อกลาง | 6060308706800320801 |
| Meta Audience Network* * ก่อนวันที่ 6 มิถุนายน 2022 เครือข่ายนี้มีชื่อว่า "Facebook Audience Network" | 10568273599589928883 |
| Meta Audience Network (การเสนอราคา)* * ก่อนวันที่ 6 มิถุนายน 2022 เครือข่ายนี้มีชื่อว่า "Facebook Audience Network (การเสนอราคา)" | 11198165126854996598 |
| Mintegral | 1357746574408896200 |
| Mintegral (การเสนอราคา) | 6250601289653372374 |
| MobFox (การเสนอราคา) | 3086513548163922365 |
| MoPub (เลิกใช้งานแล้ว) | 10872986198578383917 |
| myTarget | 8450873672465271579 |
| Nend | 9383070032774777750 |
| Nexxen (การเสนอราคา)* * ก่อนวันที่ 1 พฤษภาคม 2024 เครือข่ายนี้มีชื่อว่า "UnrulyX" | 2831998725945605450 |
| OneTag Exchange (การเสนอราคา) | 4873891452523427499 |
| OpenX (การเสนอราคา) | 4918705482605678398 |
| Pangle | 4069896914521993236 |
| Pangle (การเสนอราคา) | 3525379893916449117 |
| PubMatic (การเสนอราคา) | 3841544486172445473 |
| แคมเปญแบบจองล่วงหน้า | 7068401028668408324 |
| SK planet | 734341340207269415 |
| Sharethrough (การเสนอราคา) | 5247944089976324188 |
| Smaato (การเสนอราคา) | 3362360112145450544 |
| Sonobi (การเสนอราคา) | 3270984106996027150 |
| Tapjoy | 7295217276740746030 |
| Tapjoy (การเสนอราคา) | 4692500501762622178 |
| Tencent GDT | 7007906637038700218 |
| TripleLift (การเสนอราคา) | 8332676245392738510 |
| Unity Ads | 4970775877303683148 |
| Unity Ads (การเสนอราคา) | 7069338991535737586 |
| Verve Group (การเสนอราคา) | 5013176581647059185 |
| Vpon | 1940957084538325905 |
| Yieldmo (การเสนอราคา) | 4193081836471107579 |
| YieldOne (การเสนอราคา) | 3154533971590234104 |
| Zucks | 5506531810221735863 |
การให้รางวัลแก่ผู้ใช้
คุณควรสร้างสมดุลระหว่างประสบการณ์ของผู้ใช้และการตรวจสอบความถูกต้องของรางวัลเมื่อตัดสินใจ ว่าจะให้รางวัลแก่ผู้ใช้เมื่อใด การเรียกกลับฝั่งเซิร์ฟเวอร์อาจมีความล่าช้าก่อนที่จะ ไปถึงระบบภายนอก ดังนั้น แนวทางปฏิบัติแนะนำที่ดีที่สุดคือการใช้ การเรียกกลับฝั่งไคลเอ็นต์เพื่อให้รางวัลแก่ผู้ใช้ทันที ขณะที่ทำการ ตรวจสอบรางวัลทั้งหมดเมื่อได้รับการเรียกกลับฝั่งเซิร์ฟเวอร์ แนวทางนี้ช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีพร้อมทั้งรับประกันความถูกต้องของรางวัลที่มอบให้
อย่างไรก็ตาม สำหรับแอปพลิเคชันที่ความถูกต้องของรางวัลมีความสำคัญอย่างยิ่ง (เช่น รางวัลส่งผลต่อเศรษฐกิจในเกมของแอป) และการให้รางวัลล่าช้าเป็นสิ่งที่ยอมรับได้ การรอการเรียกกลับฝั่งเซิร์ฟเวอร์ที่ยืนยันแล้วอาจเป็นแนวทางที่ดีที่สุด
ข้อมูลที่กำหนดเอง
แอปที่ต้องการข้อมูลเพิ่มเติมในการเรียกกลับของการยืนยันฝั่งเซิร์ฟเวอร์ควรใช้
ฟีเจอร์ข้อมูลที่กำหนดเองของโฆษณาที่มีการให้รางวัล ค่าสตริงที่ตั้งค่าไว้ในออบเจ็กต์โฆษณาที่มีการให้รางวัล
จะส่งไปยังพารามิเตอร์การค้นหา custom_data ของการเรียกกลับ SSV หากไม่ได้ตั้งค่าข้อมูลที่กำหนดเอง
ค่าพารามิเตอร์การค้นหาcustom_dataจะไม่
อยู่ในการเรียกกลับ SSV
ตัวอย่างต่อไปนี้จะตั้งค่าตัวเลือก SSV หลังจากโหลดโฆษณาที่มีการให้รางวัลแล้ว
แทนที่ SAMPLE_CUSTOM_DATA_STRING ด้วยข้อมูลที่กำหนดเอง
หากต้องการตั้งค่าสตริงรางวัลที่กำหนดเอง คุณต้องตั้งค่าก่อนแสดงโฆษณา
การยืนยัน SSV ที่มีการให้รางวัลด้วยตนเอง
ขั้นตอนที่RewardedAdsVerifierคลาสใช้เพื่อยืนยัน SSV ที่ได้รับรางวัล
มีดังนี้ แม้ว่าข้อมูลโค้ดที่รวมไว้จะเป็นภาษา Java และใช้ประโยชน์จากไลบรารีของบุคคลที่สามอย่าง Tink แต่คุณก็สามารถทำตามขั้นตอนเหล่านี้ในภาษาที่ต้องการได้โดยใช้ไลบรารีของบุคคลที่สามที่รองรับ ECDSA
ดึงข้อมูลคีย์สาธารณะ
หากต้องการยืนยันการเรียกกลับ SSV ที่มีรางวัล คุณต้องมีคีย์สาธารณะที่ AdMob ให้ไว้
คุณสามารถดึงรายการคีย์สาธารณะที่จะใช้เพื่อตรวจสอบความถูกต้องของ Callback 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 แล้วดาวน์โหลดคีย์ โค้ดต่อไปนี้จะทำงานนี้ให้เสร็จสมบูรณ์และบันทึกการแสดงคีย์ในรูปแบบ JSON
ลงในตัวแปร 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 เมธอดด้านล่างจะรับสตริง JSON เช่น ตัวอย่างด้านบนเป็นอินพุต และสร้างการแมปจากค่า key_id ไปยังคีย์สาธารณะ
ซึ่งแคปซูลเป็นออบเจ็กต์ ECPublicKey จากไลบรารี Tink
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;
}
รับเนื้อหาที่จะยืนยัน
พารามิเตอร์การค้นหา 2 รายการสุดท้ายของแฮนเดิลการเรียกกลับ SSV ที่ให้รางวัลจะเป็น signature
และ key_id, ตามลำดับเสมอ พารามิเตอร์การค้นหาที่เหลือจะระบุเนื้อหา
ที่จะยืนยัน สมมติว่าคุณกำหนดค่า AdMob ให้ส่งการเรียกกลับของรางวัลไปยัง
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
โค้ดด้านล่างแสดงวิธีแยกวิเคราะห์เนื้อหาที่จะยืนยันจาก URL เรียกกลับเป็นอาร์เรย์ไบต์ 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"));
รับลายเซ็นและ key_id จาก URL เรียกกลับ
ใช้ค่า queryString จากขั้นตอนก่อนหน้าเพื่อแยกวิเคราะห์พารามิเตอร์การค้นหา signature และ key_id จาก URL เรียกกลับดังที่แสดงด้านล่าง
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);
}
}
หากเมธอดทำงานโดยไม่ส่งข้อยกเว้น แสดงว่าระบบยืนยัน URL เรียกกลับ เรียบร้อยแล้ว
คำถามที่พบบ่อย
- ฉันแคชคีย์สาธารณะที่เซิร์ฟเวอร์คีย์ของ AdMob ให้ได้ไหม
- เราขอแนะนําให้แคชคีย์สาธารณะที่เซิร์ฟเวอร์คีย์ AdMob ให้ไว้เพื่อลดจํานวนการดําเนินการที่จําเป็นในการตรวจสอบความถูกต้องของ การเรียกกลับ SSV อย่างไรก็ตาม โปรดทราบว่าระบบจะหมุนเวียนคีย์สาธารณะเป็นประจำและไม่ควรแคชคีย์นานเกิน 24 ชั่วโมง
- เซิร์ฟเวอร์คีย์ของ AdMob หมุนเวียนคีย์สาธารณะบ่อยเพียงใด
- คีย์สาธารณะที่เซิร์ฟเวอร์คีย์ของ AdMob จัดเตรียมให้จะหมุนเวียนตาม กำหนดเวลาที่เปลี่ยนแปลงได้ โปรดอย่าแคชคีย์สาธารณะนานเกิน 24 ชั่วโมงเพื่อให้การยืนยันการเรียกกลับ SSV ยังคงทำงานได้ตามที่ต้องการ
- จะเกิดอะไรขึ้นหากเข้าถึงเซิร์ฟเวอร์ของฉันไม่ได้
- Google คาดหวังรหัสการตอบกลับสถานะความสำเร็จ
HTTP 200 OKสำหรับการเรียกกลับ SSV หากเข้าถึงเซิร์ฟเวอร์ไม่ได้หรือเซิร์ฟเวอร์ไม่ส่งการตอบกลับตามที่คาดไว้ Google จะพยายามส่งการเรียกกลับ SSV อีกครั้งสูงสุด 5 ครั้งโดยเว้นช่วงครั้งละ 1 วินาที - ฉันจะยืนยันได้อย่างไรว่าการเรียกกลับ SSV มาจาก Google
- ใช้การค้นหา DNS แบบย้อนกลับเพื่อยืนยันว่าการเรียกกลับ SSV มาจาก Google