当您的广告素材在竞价中胜出时,Google 可以告知您 如果广告素材包含相关宏,则价格为原始价格。
如果您的出价工具配置为使用 OpenRTB 协议,相应广告素材
应使用 IAB 的${AUCTION_PRICE}
宏。
如果您的出价工具使用已弃用的 Google RTB 协议,则广告素材应
使用 Google 的%%WINNING_PRICE%%
宏。
当这些宏展开时,它们会在 加密形式。它们可包含在广告素材中,例如,通过 作为广告的一部分呈现的不可见像素请求:
<div> <script language='JavaScript1.1' src='https://example.com?creativeID=5837243'/> <img src='https://example.com/t.gif?price=${AUCTION_PRICE}' width='1' height='1'/> </div>
${AUCTION_PRICE}
宏还可以添加到
视频广告素材,但 VAST 中的展示网址中未包含:
https://example.com/vast/v?price=${AUCTION_PRICE}
场景
- 您的 OpenRTB 出价应用包含
${AUCTION_PRICE}
宏包含在返回给 Google 的 HTML 代码段或 VAST 网址中。 - 在未填充网络安全的内容中,Google 会将胜出价格替换为宏 base64 编码 (RFC 3548)。
- 该代码段以您选择的格式传递确认信息。对于 例如,确认信息可能会通过不可见像素的网址传递 作为广告的一部分呈现
- 在服务器上,您的应用网络安全 base64 对胜出价格进行解码 并对结果进行解密。
依赖项
您需要一个支持 SHA-1 HMAC 的加密库,例如 Openssl。
示例代码
我们提供 Java 和 C++ 示例代码,您可以通过 privatedatacommunicationprotocol 项目。
Java 示例代码使用来自 Apache 的 base64 解码器 Commons 项目。您不需要下载 Apache Commons 代码, 因为参考实现包含必要的部分,因此 都是独立的。
C++ 示例代码使用 OpenSSL base64 BIO 方法。它接受一个可在 web 环境中安全使用的 base64 编码字符串 (RFC 3548) 并对其进行解码。 通常,网络安全 base64 字符串会替换“=”填充内容为“.”(请注意, 为清晰起见而添加引号,且引号未包含在 协议),但宏替换不会填充加密价格。通过 由于 OpenSSL 无法处理 字符串。
编码
加密和解密胜出价格需要两个密钥,但它们是共享的
键。完整性密钥和加密密钥(称为 i_key
)
和 e_key
。这两个密钥都是在账号开设时提供的,
网络安全 base64 字符串,可在 Authorized Buyers 页面上找到
在出价方下
设置 >实时出价设置 >加密密钥。
完整性和加密密钥示例:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key) arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
密钥应通过网络安全解码,然后再由您的 应用:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
加密架构
价格使用自定义加密方案加密 最大限度地减少大小开销,同时确保足够的安全性。加密架构 使用密钥的 HMAC 算法 展示事件 ID。
加密价格的固定长度为 28 个字节。它由 16 字节初始化矢量,8 字节密文,4 字节完整性 签名。根据 RFC,加密的价格采用可在网络上安全使用的 base64 编码 3548 个(省略了填充字符)。因此,28 字节的加密价格 编码为一个 38 个字符的网络安全 base-64 字符串,与胜出无关 支付的价格。
加密价格示例:
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) |
数据 d 的 SHA-1 HMAC,使用密钥 k |
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 库
无需实现加密算法来编码和解码 您可以使用 <ph type="x-smartling-placeholder"></ph> DoubleClickCrypto.java.如需了解详情,请参阅 加密。