קריאות חוזרות (callback) לאימות בצד השרת הן בקשות לכתובות URL, עם פרמטרים של שאילתה שהמערכת של Google מרחיבה, שנשלחות על ידי Google למערכת חיצונית כדי להודיע לה שצריך לתגמל משתמש על אינטראקציה עם מודעה מתגמלת או עם מודעת מעברון מתגמלת. קריאות חוזרות (callback) של אימות בצד השרת (SSV) של מודעות מתגמלות מספקות שכבת הגנה נוספת מפני זיוף של קריאות חוזרות (callback) בצד הלקוח כדי לתגמל משתמשים.
במדריך הזה מוסבר איך לאמת קריאות חוזרות (callback) של אימות בצד השרת (SSV) של מודעות מתגמלות באמצעות ספריית ההצפנה של צד שלישי Tink Java Apps, כדי לוודא שפרמטרים השאילתה בקריאה החוזרת הם ערכים לגיטימיים. למרות שבמדריך הזה נעשה שימוש ב-Tink, אפשר להשתמש בכל ספרייה של צד שלישי שתומכת ב-ECDSA. אפשר גם לבדוק את השרת באמצעות כלי הבדיקה בממשק המשתמש של AdMob.
דרישות מוקדמות
- מפעילים את האימות של התגמול בצד השרת ביחידת המודעות.
שימוש ב-RewardedAdsVerifier מספריית Tink Java Apps
מאגר GitHub Tink Java Apps כולל מחלקה מסייעת RewardedAdsVerifier
שמצמצמת את כמות הקוד שנדרשת לאימות קריאה חוזרת של SSV עם תגמול.
אפשר להשתמש במחלקה הזו כדי לאמת כתובת URL של קריאה חוזרת באמצעות הקוד הבא.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
אם השיטה verify()
מופעלת בלי להעלות חריגה, כתובת ה-URL של הקריאה החוזרת אומתה בהצלחה. בקטע תגמול המשתמש מפורטות שיטות מומלצות לגבי המקרים שבהם כדאי לתגמל את המשתמשים. כדי לקבל פירוט של השלבים שמתבצעים על ידי המחלקה הזו לאימות קריאות חוזרות (callback) של SSV על מודעות מתגמלות, אפשר לקרוא את הקטע אימות ידני של SSV על מודעות מתגמלות.
פרמטרים של קריאה חוזרת (callback) בצד השרת
קריאות חוזרות (callback) לאימות בצד השרת מכילות פרמטרים של שאילתה שמתארים את האינטראקציה עם המודעה המתגמלת. בהמשך מפורטים השמות, התיאורים והערכים לדוגמה של הפרמטרים. הפרמטרים נשלחים בסדר אלפביתי.
שם פרמטר | תיאור | ערך לדוגמה |
---|---|---|
ad_network | מזהה מקור המודעות של מקור המודעות שסיפק את המודעה הזו. שמות מקורות המודעות שמתאימים לערכי המזהים מפורטים בקטע מזהים של מקורות מודעות. | 1953547073528090325 |
ad_unit | המזהה של יחידת המודעות ב-AdMob ששימש לשליחת הבקשה להצגת המודעה המתגמלת. | 2747237135 |
custom_data | מחרוזת נתונים בהתאמה אישית כפי שסופקה על ידי
ServerSideVerificationOptions::custom_data .
אם האפליקציה לא מספקת מחרוזת נתונים מותאמת אישית, ערך פרמטר השאילתה הזה לא יופיע בקריאה החוזרת מסוג SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | המפתח שישמש לאימות הקריאה החוזרת של SSV. הערך הזה ממופה למפתח ציבורי שסופק על ידי שרת המפתחות של AdMob. | 1234567890 |
reward_amount | סכום התגמול שצוין בהגדרות של יחידת המודעות. | 5 |
reward_item | פריט התגמול כפי שצוין בהגדרות של יחידת המודעות. | מטבעות |
signature | חתימה של קריאה חוזרת (callback) של SSV שנוצרה על ידי AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
חותמת זמן | חותמת הזמן של מועד קבלת התגמול על ידי המשתמש, כזמן מערכת באלפיות השנייה. | 1507770365237823 |
transaction_id | מזהה ייחודי בקידוד הקסדצימלי לכל אירוע הענקת תגמול שנוצר על ידי AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | מזהה המשתמש כפי שסופק על ידי
ServerSideVerificationOptions::user_id .
אם האפליקציה לא מספקת מזהה משתמש, פרמטר השאילתה הזה לא יופיע בקריאה החוזרת של SSV. |
1234567 |
מזהים של מקורות למודעות
שמות ומזהים של מקורות תנועה
שם מקור המודעה | מזהה מקור המודעות |
---|---|
Ad Generation (bidding) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (בידינג) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
רשת AdMob | 5450213213286189855 |
AdMob Network Waterfall | 1215381445328257950 |
Applovin | 1063618907739174004 |
Applovin (בידינג) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform (bidding) | 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 (bidding). | 4692500501762622185 |
LG U+AD | 18298738678491729107 |
LINE Ads Network | 3025503711505004547 |
Magnite DV+ (בידינג) | 3993193775968767067 |
maio | 7505118203095108657 |
maio (bidding) | 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 (bidding) | 8332676245392738510 |
Unity Ads | 4970775877303683148 |
Unity Ads (בידינג) | 7069338991535737586 |
Verve Group (בידינג) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Yieldmo (בידינג) | 4193081836471107579 |
YieldOne (בידינג) | 3154533971590234104 |
Zucks | 5506531810221735863 |
תגמול המשתמש
חשוב לאזן בין חוויית המשתמש לבין אימות התגמול כשמחליטים מתי לתגמל משתמש. יכול להיות שיהיו עיכובים בהגעת קריאות חוזרות (callback) בצד השרת למערכות חיצוניות. לכן, שיטת העבודה המומלצת היא להשתמש בקריאה חוזרת (callback) בצד הלקוח כדי לתגמל את המשתמש באופן מיידי, ובמקביל לבצע אימות של כל התגמולים עם קבלת קריאות חוזרות בצד השרת. הגישה הזו מספקת חוויית משתמש טובה, וגם מבטיחה שהתגמולים שניתנים הם תקפים.
עם זאת, באפליקציות שבהן תוקף הפרס הוא קריטי (לדוגמה, אם הפרס משפיע על הכלכלה במשחק באפליקציה) ועיכובים במתן הפרסים הם מקובלים, יכול להיות שהגישה הטובה ביותר היא להמתין לקריאה החוזרת (callback) מאומתת בצד השרת.
נתונים בהתאמה אישית
אפליקציות שדורשות נתונים נוספים בקריאות חוזרות (callback) של אימות בצד השרת צריכות להשתמש בתכונה 'נתונים מותאמים אישית' של מודעות מתגמלות. כל ערך מחרוזת שמוגדר באובייקט של מודעה מתגמלת מועבר לפרמטר השאילתה custom_data
של הקריאה החוזרת לאימות מצד השרת. אם לא מוגדר ערך נתונים מותאם אישית, הערך של פרמטר השאילתה custom_data
לא יופיע בקריאה החוזרת של SSV.
דוגמת הקוד הבאה מראה איך להגדיר נתונים מותאמים אישית באובייקט של מודעה מתגמלת לפני שליחת בקשה להצגת מודעה.
firebase::gma::RewardedAd* rewarded_ad; rewarded_ad = new firebase::gma::RewardedAd(); firebase::gma::RewardedAd::ServerSideVerificationOptions options; options.custom_data = "SAMPLE_CUSTOM_DATA_STRING"; rewarded_ad->SetServerSideVerificationOptions(options);
אם רוצים להגדיר את מחרוזת התגמול בהתאמה אישית, צריך לעשות זאת לפני הצגת המודעה.
אימות ידני של אימות בצד השרת לצפייה במודעות מתגמלות
בהמשך מפורטים השלבים שמבצעת המחלקה RewardedAdsVerifier
כדי לאמת SSV עם תגמול. קטעי הקוד שמופיעים במאמר כתובים ב-Java ומתבססים על ספריית הצד השלישי Tink, אבל אתם יכולים ליישם את השלבים האלה בכל שפה שתבחרו, באמצעות כל ספריית צד שלישי שתומכת ב-ECDSA.
אחזור מפתחות ציבוריים
כדי לאמת קריאה חוזרת (callback) של 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;
}
קבלת תוכן לאימות
שני הפרמטרים האחרונים של שאילתות בקריאות חוזרות (callback) של SSV עם תגמול הם תמיד signature
ו-key_id,
, בסדר הזה. בשאר הפרמטרים של השאילתה מצוין התוכן שצריך לאמת. נניח שהגדרתם את AdMob לשליחת קריאות חוזרות (callback) על תגמולים אל https://www.myserver.com/mypath
. קטע הקוד שלמטה מציג דוגמה לקריאה חוזרת (callback) של 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 של הקריאה החוזרת (callback)
בעזרת הערך 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 לקריאה חוזרת (callback) באמצעות המפתח הציבורי המתאים. לוקחים את המיפוי שמוחזר מהשיטה 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 לקריאה חוזרת (callback) אומתה בהצלחה.
שאלות נפוצות
- האם אפשר לשמור במטמון את המפתח הציבורי שסופק על ידי שרת המפתחות של AdMob?
- מומלץ לשמור במטמון את המפתח הציבורי שסופק על ידי שרת המפתחות של AdMob כדי לצמצם את מספר הפעולות שנדרשות לאימות קריאות חוזרות של SSV. עם זאת, חשוב לזכור שהמפתחות הציבוריים מתחלפים באופן קבוע, ולכן לא מומלץ לשמור אותם במטמון למשך יותר מ-24 שעות.
- באיזו תדירות מתבצעת רוטציה של המפתחות הציבוריים שסופקו על ידי שרת המפתחות של AdMob?
- המפתחות הציבוריים שמועברים משרת המפתחות של AdMob מתחלפים לפי לוח זמנים משתנה. כדי לוודא שהאימות של קריאות חוזרות (callback) של SSV ימשיך לפעול כמצופה, לא מומלץ לשמור במטמון מפתחות ציבוריים למשך יותר מ-24 שעות.
- מה קורה אם אי אפשר להגיע לשרת שלי?
- Google מצפה לקבל קוד תגובה של סטטוס הצלחה
HTTP 200 OK
עבור קריאות חוזרות (callback) של SSV. אם אי אפשר להגיע לשרת או שהוא לא מספק את התשובה הצפויה, Google תנסה לשלוח שוב את הקריאות החוזרות של SSV עד חמש פעמים במרווחי זמן של שנייה אחת. - איך אפשר לוודא שהקריאות החוזרות (callback) של SSV מגיעות מ-Google?
- משתמשים בשאילתת DNS הפוכה כדי לוודא שהקריאות החוזרות של SSV מגיעות מ-Google.