メインコンテンツまでスキップ

Encrypting Requests and Decrypting Responses

注記

パブリッシャーで、クライアント側にUID2を実装している場合、暗号化と復号化は、Prebid.js (UID2 Client-Side Integration Guide for Prebid.js を参照してください) や JavaScript SDK (Client-Side Integration Guide for JavaScript を参照してください) などの実装によって自動的に管理されます。

ほとんどすべての UID2 endpoints では、エンドポイントに送られるリクエストは encrypted され、エンドポイントからのレスポンスは decrypted する必要があります。

唯一の例外は、POST /token/refresh エンドポイントへのリクエストは暗号化する必要がないことです。

UID2 API リクエストの暗号化と各レスポンスの復号化について知っておく必要があるのは、以下のとおりです:

Workflow

UID2 API のリクエスト・レスポンスワークフローは、以下のステップです:

  1. 入力パラメータを含むリクエストボディを JSON 形式で用意します。
  2. リクエスト JSON を暗号化前リクエストデータエンベローブ でラップします。
  3. AES/GCM/NoPadding アルゴリズムと秘密鍵でエンベローブを暗号化します。
  4. 暗号化リクエストエンベローブ を組み立てます。
  5. 暗号化されたリクエストを送信し、暗号化されたレスポンスを受信します。
  6. 暗号化レスポンスエンベローブ を解析します。
  7. レスポンスエンベローブのデータを復号化します。
  8. 得られた 復号化済みレスポンスデータエンベローブ を解析します。
  9. (オプション、推奨) レスポンスエンベローブの nonce がリクエストエンベローブの nonce と一致することを確認します。
  10. 暗号化されていないエンベローブからレスポンス JSON オブジェクトを抽出します。

encrypting requests and decrypting responses のコード例は、Step 2-10 を自動化するのに役立ち、アプリケーションでこれらのステップを実装する方法のリファレンスとなります。

各 UID2 endpoints では、JSON ボディのフォーマットの要件とパラメータを説明し、呼び出し例を含め、復号化されたレスポンスを示しています。以下のセクションでは、暗号化と復号化のコード例、フィールドレイアウトの要件、リクエストとレスポンスの例を示します。

Encrypting Requests

リクエストを暗号化するコードを自分で書くか、UID2 SDK を使うか、提供されているコード例のいずれかを使うかの選択肢があります(Encryption and Decryption Code Examples を参照してください)。自分でコードを書く場合は、unencrypted request data envelopeEncrypted Request Envelope に記載されているフィールドレイアウトの要件に従うようにしてください。

Unencrypted Request Data Envelope

以下の表に、リクエスト暗号化コードのフィールドレイアウトを示します。

Offset (Bytes)Size (Bytes)Description
08UNIX タイムスタンプ (ミリ秒単位) です。int64 のビッグエンディアンでなければなりません。
88Nonce: リプレイ攻撃から保護するために使用されるランダムな 64 ビットのデータです。対応する 復号化済みレスポンスデータエンベローブ には、レスポンスが有効とみなされるために同じ nonce 値が含まれていなければなりません。
16NUTF-8 エンコーディングでシリアライズされたリクエスト JSON ドキュメントをペイロードとします。

Encrypted Request Envelope

次の表は、リクエスト暗号化コードのフィールドレイアウトを説明するものです。

Offset (Bytes)Size (Bytes)Description
01エンベローブフォーマットのバージョン。1 でなければなりません。
11296 ビットの初期化ベクトル (IV)、データ暗号化のランダム化に使用されます。
13Nペイロード(暗号化前リクエストデータエンベローブ) は AES/GCM/NoPadding アルゴリズムで暗号化されます。
13 + N16データの整合性を確認するために使用される 128 ビット GCM 認証タグです。

Decrypting Responses

レスポンスを復号化するコードを自分で書くか、UID2 SDKを使うか、提供されているコード例のいずれかを使うかの選択肢があります(Encryption and Decryption Code Examples を参照してください)。独自のコードを書く場合は、Encrypted Response Envelope および Encrypted Response Envelope に記載されているフィールドレイアウトの要件に従うようにしてください。

注記

レスポンスは、サービスが HTTP ステータスコード 200 を返す場合のみ、暗号化されます。

Encrypted Response Envelope

次の表は、レスポンス復号化コードのフィールドレイアウトを説明するものです。

Offset (Bytes)Size (Bytes)Description
01296 ビットの初期化ベクトル (IV)、データ暗号化のランダム化に使用されます。
12Nペイロード(復号化済みレスポンスデータエンベローブ) は、AES/GCM/NoPadding アルゴリズムで暗号化されています。
12 + N16データの整合性を確認するために使用される 128 ビット GCM 認証タグ。

Unencrypted Response Data Envelope

次の表は、レスポンス復号化コードのフィールドレイアウトを説明するものです。

Offset (Bytes)Size (Bytes)Description
08UNIX タイムスタンプ (ミリ秒単位) です。int64 のビッグエンディアンでなければなりません。
88Nonce: レスポンスが有効であるとみなされるためには、これは 暗号化前リクエストデータエンベローブ の nonce と一致する必要があります。
16NUTF-8 エンコーディングでシリアライズされたレスポンス JSON ドキュメントをペイロードとします。

Response Example

例えば、先行例 のメールアドレスに対する POST /token/generate リクエストに対する復号されたレスポンスは、次のようになることが考えられます:

{
"body": {
"advertising_token": "AgAAAQFt3aNLXKXEyWS8Tpezcymk1Acv3n+ClOHLdAgqR0kt0Y+pQWSOVaW0tsKZI4FOv9K/rZH9+c4lpm2DBpmFJqjdF6FAaAzva5vxDIX/67UOspsYtiwxH73zU7Fj8PhVf1JcpsxUHRHzuk3vHF+ODrM13A8NAVlO1p0Wkb+cccIIhQ==",
"user_token": "AgAAAPpTqz7/Z+40Ue5G3XOM2RiyU6RS9Q5yj1n7Tlg7PN1K1LZWejvo8Er7A+Q8KxdXdj0OrKRf/XEGWsyUJscRNu1bg/MK+5AozvoJKUca8b10eQdYU86ZOHPH7pFnFhD5WHs=",
"refresh_token": "AAAAAQLMcnV+YE6/xoPDZBJvJtWyPyhF9QTV4242kFdT+DE/OfKsQ3IEkgCqD5jmP9HuR4O3PNSVnCnzYq2BiDDz8SLsKOo6wZsoMIn95jVWBaA6oLq7uUGY5/g9SUOfFmX5uDXUvO0w2UCKi+j9OQhlMfxTsyUQUzC1VQOx6ed/gZjqH/Sw6Kyk0XH7AlziqSyyXA438JHqyJphGVwsPl2LGCH1K2MPxkLmyzMZ2ghTzrr0IgIOXPsL4lXqSPkl/UJqnO3iqbihd66eLeYNmyd1Xblr3DwYnwWdAUXEufLoJbbxifGYc+fPF+8DpykpyL9neq3oquxQWpyHsftnwYaZT5EBZHQJqAttHUZ4yQ==",
"identity_expires": 1654623500142,
"refresh_expires": 1657214600142,
"refresh_from": 1654622900142,
"refresh_response_key": "wR5t6HKMfJ2r4J7fEGX9Gw=="
},
"status": "success"
}

Encryption and Decryption Code Examples

このセクションには、さまざまなプログラミング言語による暗号化と復号化のコード例が示されています。

POST /token/refresh エンドポイントでは、POST /token/generate または POST /token/refresh へのコールで事前に取得した refresh_tokenrefresh_response_key の値を使用します。

Encryption and Decryption Code Examples

注記

Windows の場合、PowerShell の代わりに Windows コマンドプロンプトを使用している場合は、JSON を囲むシングルクォートも削除する必要があります。例えば、echo {"email": "test@example.com"} とします。

Prerequisites and Notes

コードサンプルを使用する前に、使用している言語の前提条件と注意事項を確認してください。

以下のコードサンプルは Python を使ってリクエストを暗号化し、レスポンスを復号化します。必要なパラメータはコード例の一番上に示されており、 python3 uid2_request.py を実行することで得ることができます。

注記

Windowsの場合は python3python に置き換えてください。

Python のコードには pycryptodomexrequests パッケージが必要です。これらは以下のようにしてインストールできます:

pip install pycryptodomex
pip install requests

Code Example

使いたいコードサンプルを選んでください。Prerequisites and Notes を忘れずに確認してください。

uid2_request.py
"""
Usage:
echo '<json>' | python3 uid2_request.py <url> <api_key> <client_secret>

Example:
echo '{"email": "test@example.com"}' | python3 uid2_request.py https://prod.uidapi.com/v2/token/generate PRODGwJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg= wJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg=


Refresh Token Usage:
python3 uid2_request.py <url> --refresh-token <refresh_token> <refresh_response_key>

Refresh Token Usage example:
python3 uid2_request.py https://prod.uidapi.com/v2/token/refresh --refresh-token AAAAAxxJ...(truncated, total 388 chars) v2ixfQv8eaYNBpDsk5ktJ1yT4445eT47iKC66YJfb1s=

"""

import base64
import os
import sys
import time
import json

import requests
from Cryptodome.Cipher import AES

def b64decode(b64string, param):
try:
return base64.b64decode(b64string)
except Exception:
print(f"Error: <{param}> is not base64 encoded")
sys.exit()

if len(sys.argv) != 4 and len(sys.argv) != 5:
print(__doc__)
sys.exit()

url = sys.argv[1]

is_refresh = 1 if sys.argv[2] == '--refresh-token' else 0
if is_refresh:
refresh_token = sys.argv[3]
secret = b64decode(sys.argv[4], "refresh_response_key")
print(f"\nRequest: Sending refresh_token to {url}\n")
http_response = requests.post(url, refresh_token)
else:
api_key = sys.argv[2]
secret = b64decode(sys.argv[3], "client_secret")
payload = "".join(sys.stdin.readlines())

iv = os.urandom(12)
cipher = AES.new(secret, AES.MODE_GCM, nonce=iv)

millisec = int(time.time() * 1000)
request_nonce = os.urandom(8)

print(f"\nRequest: Encrypting and sending to {url} : {payload}")

body = bytearray(millisec.to_bytes(8, 'big'))
body += bytearray(request_nonce)
body += bytearray(bytes(payload, 'utf-8'))

ciphertext, tag = cipher.encrypt_and_digest(body)

envelope = bytearray(b'\x01')
envelope += bytearray(iv)
envelope += bytearray(ciphertext)
envelope += bytearray(tag)

base64Envelope = base64.b64encode(bytes(envelope)).decode()

http_response = requests.post(url, base64Envelope, headers={"Authorization": "Bearer " + api_key})

# Decryption
response = http_response.content
if http_response.status_code != 200:
print(f"Response: Error HTTP status code {http_response.status_code}", end=", check api_key\n" if http_response.status_code == 401 else "\n")
print(response.decode("utf-8"))
else:
resp_bytes = base64.b64decode(response)
iv = resp_bytes[:12]
data = resp_bytes[12:len(resp_bytes) - 16]
tag = resp_bytes[len(resp_bytes) - 16:]

cipher = AES.new(secret, AES.MODE_GCM, nonce=iv)
decrypted = cipher.decrypt_and_verify(data, tag)

if is_refresh != 1:
json_resp = json.loads(decrypted[16:].decode("utf-8"))
else:
json_resp = json.loads(decrypted.decode("utf-8"))

print("Response JSON:")
print(json.dumps(json_resp, indent=4))