使用 的广告网络
用于通过 Authorized Buyers 填充广告的 JavaScript 代码有资格
接收 Android 和 iOS 设备的广告客户标识符
该信息通过 %%EXTRA_TAG_DATA%%
或
由 JavaScript 代码管理的 %%ADVERTISING_IDENTIFIER%%
宏
Authorized Buyers 用户数量。本部分的其余内容将重点介绍如何提取
%%EXTRA_TAG_DATA%%
,但可以看到
<ph type="x-smartling-placeholder"></ph>
使用 IDFA 或广告 ID 进行再营销,了解详情
在 %%ADVERTISING_IDENTIFIER%%
加密的 proto 缓冲区中
MobileAdvertisingId
。
时间轴
- 广告联盟更新其 JavaScript 应用内代码
通过 Authorized Buyers 界面使用
添加
%%EXTRA_TAG_DATA%%
宏(如下所述)。 - 在投放时,该应用通过 Google 移动广告 SDK,同时 安全地传递广告客户标识符
- 应用收到带有
%%EXTRA_TAG_DATA%%
的 JavaScript 标记 宏进行填充。 - 应用运行此代码,向广告联盟发出获胜调用请求 。
- 要使用这些信息(通过它们创收),广告联盟必须处理
协议缓冲区:
<ph type="x-smartling-placeholder">
- </ph>
- 使用 WebSafeBase64 将网络安全字符串解码回字节串。
- 使用下面列出的方案对其进行解密。
- 反序列化 proto 并从中获取广告客户 ID ExtraTagData.advertising_id 或 ExtraTagData.hashed_idfa。
依赖项
- WebSafeBase64 编码器。
- 支持 SHA-1 HMAC 的加密库,例如 Openssl。
- Google 协议 缓冲区编译器。
解码网络安全字符串
因为通过 %%EXTRA_TAG_DATA%%
宏发送的信息
必须通过网址发送,Google 服务器会使用可在网络中安全使用的 base64 (RFC 3548) 对其进行编码。
在尝试之前 因此,您必须将 ASCII 字符解码回 字节串。以下示例 C++ 代码基于 OpenSSL 项目的 BIO_f_base64(),是 Google 的示例的一部分 解密代码。
string AddPadding(const string& b64_string) { if (b64_string.size() % 4 == 3) { return b64_string + "="; } else if (b64_string.size() % 4 == 2) { return b64_string + "=="; } return b64_string; } // Adapted from http://www.openssl.org/docs/man1.1.0/crypto/BIO_f_base64.html // Takes a web safe base64 encoded string (RFC 3548) and decodes it. // Normally, web safe base64 strings have padding '=' replaced with '.', // but we will not pad the ciphertext. We add padding here because // openssl has trouble with unpadded strings. string B64Decode(const string& encoded) { string padded = AddPadding(encoded); // convert from web safe -> normal base64. int32 index = -1; while ((index = padded.find_first_of('-', index + 1)) != string::npos) { padded[index] = '+'; } index = -1; while ((index = padded.find_first_of('_', index + 1)) != string::npos) { padded[index] = '/'; } // base64 decode using openssl library. const int32 kOutputBufferSize = 256; char output[kOutputBufferSize]; BIO* b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO* bio = BIO_new_mem_buf(const_cast(padded.data()), padded.length()); bio = BIO_push(b64, bio); int32 out_length = BIO_read(bio, output, kOutputBufferSize); BIO_free_all(bio); return string(output, out_length); }
加密字节串的结构
将 ASCII 字符解码回字节串后,就可以 解密文件。加密字节串包含 3 个部分:
initialization_vector
:16 个字节。ciphertext
:20 字节的系列部分。integrity_signature
:4 个字节。
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
ciphertext
字节数组分为多个 20 字节
部分,但最后一部分可能包含
1 至 20 个字节(含边界值)。对于原始内容的每个部分
byte_array
,对应的 20 字节 ciphertext
生成为:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
其中 ||
是串联。
定义
不定额 | 详细信息 |
---|---|
initialization_vector |
16 个字节 - 对展示具有唯一性。 |
encryption_key |
32 个字节 - 在设置账号时提供。 |
integrity_key |
32 个字节 - 在设置账号时提供。 |
byte_array |
序列化的 ExtraTagData 对象,分为 20 个字节的部分。 |
counter_bytes |
显示部分序数的字节值,如下所示。 |
final_message |
通过 %%EXTRA_TAG_DATA%% 宏发送的总字节数组(减去 WebSafeBase64 编码)。 |
运算符 | 详细信息 |
---|---|
hmac(key, data) |
SHA-1 HMAC,使用 key 对 data 进行加密。 |
a || b |
字符串 a 与字符串 b 串联。 |
计算 counter_bytes
counter_bytes
标记每个 20 字节
ciphertext
。请注意,最后一部分可能包含 1 到
20 个字节(含边界值)。使用正确的值填充 counter_bytes
在运行 hmac()
函数时,计算 20 个字节的大小
(包括余下部分),并使用以下参考表:
章节编号 | counter_bytes 值 |
---|---|
0 次 | 无 |
1 ... 256 | 1 个字节。值按顺序从 0 到 255 递增。 |
257 ... 512 | 2 个字节。第一个字节的值为 0,第二个字节的值 从 0 到 255 递增。 |
513 ... 768 | 3 个字节。前两个字节的值为 0,最后一个字节的值 从 0 到 255 递增。 |
加密架构
加密机制基于解密 比邻商家定位信号。
序列化:ExtraTagData 对象的实例,如下所示 首先通过协议缓冲区 将
SerializeAsString()
转换为字节数组。加密:然后使用 自定义加密架构,最大限度地降低数据大小开销,同时确保 足够的安全性。加密架构使用密钥加密的 HMAC 算法 基于
initialization_vector
的秘密键盘, 展示事件。
加密伪代码
byte_array = SerializeAsString(ExtraTagData object) pad = hmac(encryption_key, initialization_vector || counter_bytes ) // for each 20-byte section of byte_array ciphertext = pad <xor> byte_array // for each 20-byte section of byte_array integrity_signature = hmac(integrity_key, byte_array || initialization_vector) // first 4 bytes final_message = initialization_vector || ciphertext || integrity_signature
解密机制
您的解密代码必须 1) 使用相应加密配置解密协议缓冲区 密钥,以及 2) 使用完整性密钥验证完整性位。密钥将 您在设置账号时提供给您的在创作过程中 构建您的实现。在大多数情况下,您应该能够 示例代码,并根据需要进行调整。
- Generate yourpad:
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR:将此结果与
<xor>
的 密文以逆转加密。 - 验证:完整性签名通过传递 4 个字节的
HMAC(integrity_key, byte_array || initialization_vector)
解密伪代码
// split up according to length rules (initialization_vector, ciphertext, integrity_signature) = final_message // for each 20-byte section of ciphertext pad = hmac(encryption_key, initialization_vector || counter_bytes) // for each 20-byte section of ciphertext byte_array = ciphertext <xor> pad confirmation_signature = hmac(integrity_key, byte_array || initialization_vector) success = (confirmation_signature == integrity_signature)
C++ 代码示例
该部分提供了完整 解密 示例代码。
bool DecryptByteArray( const string& ciphertext, const string& encryption_key, const string& integrity_key, string* cleartext) { // Step 1. find the length of initialization vector and clear text. const int cleartext_length = ciphertext.size() - kInitializationVectorSize - kSignatureSize; if (cleartext_length < 0) { // The length cannot be correct. return false; } string iv(ciphertext, 0, kInitializationVectorSize); // Step 2. recover clear text cleartext->resize(cleartext_length, '\0'); const char* ciphertext_begin = string_as_array(ciphertext) + iv.size(); const char* const ciphertext_end = ciphertext_begin + cleartext->size(); string::iterator cleartext_begin = cleartext->begin(); bool add_iv_counter_byte = true; while (ciphertext_begin < ciphertext_end) { uint32 pad_size = kHashOutputSize; uchar encryption_pad[kHashOutputSize]; if (!HMAC(EVP_sha1(), string_as_array(encryption_key), encryption_key.length(), (uchar*)string_as_array(iv), iv.size(), encryption_pad, &pad_size)) { printf("Error: encryption HMAC failed.\n"); return false; } for (int i = 0; i < kBlockSize && ciphertext_begin < ciphertext_end; ++i, ++cleartext_begin, ++ciphertext_begin) { *cleartext_begin = *ciphertext_begin ^ encryption_pad[i]; } if (!add_iv_counter_byte) { char& last_byte = *iv.rbegin(); ++last_byte; if (last_byte == '\0') { add_iv_counter_byte = true; } } if (add_iv_counter_byte) { add_iv_counter_byte = false; iv.push_back('\0'); } }
从广告网络协议缓冲区获取数据
对传入的数据进行解码和解密后,
%%EXTRA_TAG_DATA%%
,您现在可以反序列化协议缓冲区了
并获取用于定位的广告客户标识符。
如果您不熟悉协议缓冲区,请参阅我们的文档。
定义
广告联盟协议缓存的定义如下所示:
message ExtraTagData { // advertising_id can be Apple's identifier for advertising (IDFA) // or Android's advertising identifier. When the advertising_id is an IDFA, // it is the plaintext returned by iOS's [ASIdentifierManager // advertisingIdentifier]. For hashed_idfa, the plaintext is the MD5 hash of // the IDFA. Only one of the two fields will be available, depending on the // version of the SDK making the request. Later SDKs provide unhashed values. optional bytes advertising_id = 1; optional bytes hashed_idfa = 2; }
您需要使用 ParseFromString()
对其进行反序列化,如
C++ 协议缓冲区文档。
如需详细了解 Android advertising_id
和 iOS
hashed_idfa
字段,请参阅解密
广告 ID 和定位移动应用
带有 IDFA 的广告资源。
Java 库
无需实现加密算法来编码和解码 广告网络的广告客户标识符,您可以使用 <ph type="x-smartling-placeholder"></ph> DoubleClickCrypto.java.如需了解详情,请参阅 加密。