料金の確認の復号

クリエイティブがオークションで落札された場合、クリエイティブを定義する HTML スニペットまたは VAST URL に WINNING_PRICE マクロが含まれている場合、Google は落札価格を通知できます。落札料金は暗号化された形式で返されます。以降のトピックでは、アプリケーションで落札価格情報を復号する方法について説明します。

WINNING_PRICE マクロをクリエイティブに組み込むことができます。たとえば、目に見えないピクセルのリクエストで、広告の一部としてレンダリングできます。

<div>
  <script language='JavaScript1.1' src='https://example.com?creativeID=5837243'/>
  <img src='https://example.com/t.gif?price=%%WINNING_PRICE%%' width='1' height='1'/>
</div>

WINNING_PRICE マクロは、動画クリエイティブの VAST URL にも使用できます(ただし、VAST のインプレッション URL には使用できません)。

https://example.com/vast/v?price=%%WINNING_PRICE%%

シナリオ

  1. アプリケーションでは、Google に返す HTML スニペットまたは VAST URL に WINNING_PRICE マクロが含まれています。
  2. Google は、パディングなしのウェブセーフ base64 エンコード(RFC 3548)のマクロを落札価格に置き換えます。
  3. スニペットは、選択した形式で確認を渡します。たとえば、広告の一部として表示される非表示ピクセルのリクエストの URL で確認が渡されることがあります。
  4. サーバーで、アプリケーションのウェブセーフな Base64 が落札価格情報をデコードし、結果を復号します。

依存関係

Openssl などの SHA-1 HMAC をサポートする暗号ライブラリが必要になります。

サンプルコード

サンプルコードは Java と C++ で提供されており、privatedatacommunicationprotocol プロジェクトからダウンロードできます。

  • Java サンプルコードでは、Apache Commons プロジェクトの base64 デコーダを使用しています。Apache Commons コードをダウンロードする必要はありません。リファレンス実装には必要な部分が含まれており、自己完結型です。

  • C++ サンプルコードでは、OpenSSL base64 BIO メソッドを使用しています。ウェブセーフな Base64 でエンコードされた文字列(RFC 3548)を受け取り、デコードします。通常、ウェブセーフの Base64 文字列では「=」のパディングが「.」に置き換えられます(読みやすくするために引用符は付けられ、プロトコルには含まれません)。ただし、マクロ置換によって暗号化された価格がパディングされることはありません。OpenSSL ではパディングされていない文字列には問題があるため、リファレンス実装ではパディングが追加されます。

エンコード

落札価格の暗号化と復号には、共有される 2 つのシークレット キーが必要です。整合性鍵と暗号鍵(それぞれ i_keye_key)。どちらの鍵も、アカウント設定時にウェブセーフな Base64 文字列として提供されます。これらの鍵は、認定バイヤーのページの [入札者(ビッダー)] > [RTB 設定] > [暗号鍵] で確認できます。

整合性鍵と暗号鍵の例:

skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=  // Encryption key (e_key)
arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=  // Integrity key (i_key)

鍵は、アプリケーションでウェブセーフにデコードしてから、Base64 デコードする必要があります。

e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=')
i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')

暗号化スキーム

料金は、適切なセキュリティを確保しながらサイズのオーバーヘッドを最小限に抑えるように設計されたカスタム暗号化スキームを使用して暗号化されます。この暗号化スキームでは、鍵付き HMAC アルゴリズムを使用して、一意のインプレッション イベント ID に基づいてシークレット パッドが生成されます。

暗号化された価格は 28 バイトの固定長です。これは、16 バイトの初期化ベクトル、8 バイトの暗号テキスト、4 バイトの整合性シグネチャで構成されます。暗号化された価格は、RFC 3548 に従ってウェブセーフの Base64 エンコードされ、パディング文字は省略されます。したがって、28 バイトの暗号化価格は、支払う落札価格に関係なく、38 文字のウェブセーフ Base64 文字列としてエンコードされます。

暗号化された価格の例:

YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw  // 100 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA  // 1900 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw  // 2700 CPI micros

暗号化形式は次のとおりです。

{initialization_vector (16 bytes)}{encrypted_price (8 bytes)}
{integrity (4 bytes)}

価格は <price xor HMAC(encryption_key, initialization_vector)> として暗号化されるため、復号で HMAC(encryption_key,initialization_vector) と暗号化された価格を使用して XOR が計算され、暗号化が逆転します。整合性ステージでは、4 バイトの <HMAC(integrity_key, price||initialization_vector)> を使用します。ここで、|| は連結です。

入力
iv 初期化ベクトル(16 バイト - インプレッションに固有)
e_key 暗号鍵(32 バイト - アカウント設定時に提供されます)
i_key 整合性キー(32 バイト - アカウント設定時に提供)
price (8 バイト - アカウントの通貨のマイクロ単位)
Notation
hmac(k, d) キー k を使用したデータ d の SHA-1 HMAC
a || b 文字列 a が文字列 b と連結されます。
擬似コード
pad = hmac(e_key, iv)  // first 8 bytes
enc_price = pad <xor> price
signature = hmac(i_key, price || iv)  // first 4 bytes

final_message = WebSafeBase64Encode( iv || enc_price || signature )

復号スキーム

復号コードは、暗号鍵を使用して価格を復号し、整合性キーで整合性ビットを検証する必要があります。鍵は設定時に提供されます。実装を構造化する方法の詳細に制限はありません。ほとんどの場合、サンプルコードを必要に応じて調整できます。

入力
e_key 暗号鍵、32 バイト - アカウント設定時に提供される
i_key 整合性キー、32 バイト - アカウント設定時に提供される
final_message ウェブセーフ Base64 でエンコードされた 38 文字
擬似コード
// Base64 padding characters are omitted.
// Add any required base64 padding (= or ==).
final_message_valid_base64 = AddBase64Padding(final_message)

// Web-safe decode, then base64 decode.
enc_price = WebSafeBase64Decode(final_message_valid_base64)

// Message is decoded but remains encrypted.
(iv, p, sig) = enc_price // Split up according to fixed lengths.
price_pad = hmac(e_key, iv)
price = p <xor> price_pad

conf_sig = hmac(i_key, price || iv)
success = (conf_sig == sig)

古いレスポンス攻撃を検出する

古いレスポンス(リプレイ攻撃)を検出するには、タイムゾーンの違いを考慮したうえで、システム時刻と大幅に異なるタイムスタンプでレスポンスをフィルタすることをおすすめします。

初期化ベクトルの最初の 8 バイトにタイムスタンプが含まれます。次の C++ 関数で読み取ることができます。

void GetTime(const char* iv, struct timeval* tv) {
    uint32 val;
    memcpy(&val, iv, sizeof(val));
    tv->tv_sec = htonl(val);
    memcpy(&val, iv+sizeof(val), sizeof(val));
    tv->tv_usec = htonl(val)
}

タイムスタンプは、次の C++ コードを使用して、人が読める形式に変換できます。

struct tm tm;
localtime_r(&tv->tv_sec, &tm);

printf("%04d-%02d-%02d|%02d:%02d:%02d.%06ld",
       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
       tm.tm_hour, tm.tm_min, tm.tm_sec,
       tv_.tv_usec);

Java ライブラリ

落札価格をエンコードおよびデコードする暗号アルゴリズムを実装する代わりに、 DoubleClickCrypto.java を使用できます。詳細については、暗号化をご覧ください。