Index 1. ๊ฐ์ ๋ฒ์ฆ๋น SIS ๊ด๊ณ ์ ํ์ ์ด์ฉํ๊ธฐ ์ํ ๊ฐ์ด๋์
๋๋ค. ํ์ ์ ๋ณด๋ฅผ pquery ํํ๋ก ๋๊ฒจ์ฃผ์
์ผ ๊ด๊ณ ํ ๋น์ด ๊ฐ๋ฅํฉ๋๋ค.
2. ๊ธฐ๋ณธ URL ๊ตฌ์กฐ https://ad.buzzvil.com/action/api/ads/uahub/buzzad?pquery=[์ธ์ฝ๋ฉ๋_ํ๋ผ๋ฏธํฐ]&custom=[์ปค์คํ
_ํ๋ผ๋ฏธํฐ]&custom2=[์ปค์คํ
2_ํ๋ผ๋ฏธํฐ]
2025.07.02 pquery ํค ๋์ p๋ก๋ ์ง์
๊ฐ๋ฅํฉ๋๋ค.
3. ํ๋ผ๋ฏธํฐ (pquery) pquery ํ๋ผ๋ฏธํฐ๋ ๋ค์ ์ ๋ณด๋ฅผ ํฌํจํ JSON ๊ฐ์ฒด๋ฅผ URI ์ธ์ฝ๋ฉ ํ Base64๋ก ์ธ์ฝ๋ฉํ์ฌ ์์ฑํฉ๋๋ค.
3.1 ํ์ ํ๋ผ๋ฏธํฐ
unit_id
๋ฒ์ฆ๋น์์ ๋ฐ๊ธ๋๋ฆฐ ๊ณ ์ ์๋ณ์
1234567
puid
๋งค์ฒด์ฌ ์ํธํ ์ ์ ID
"user123"
ifa
๊ด๊ณ ID
"a31752d2-5d7e-4f41-a45c-af4d39d2fb2d"
client_ip
์ฌ์ฉ์์ IP ์ฃผ์
"192.168.1.1"
platform
์ด์ ์ฒด์ ์ ๋ณด
"A" (Android) ๋๋ "I" (iOS)
3.2 ์ ํ์ ํ๋ผ๋ฏธํฐ
birthday
์๋
์์ผ (์ฐ์ ์์ ๋์)
"1990-01-01"
year_of_birth
์ถ์๋
๋
"1990"
sex
์ฑ๋ณ
"M" ๋๋ "F"
region
์ง์ญ
"์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ"
device_name
๋จ๋ง๊ธฐ๊ธฐ ์ ๋ณด
"SHV-E250S"
carrier
ํต์ ์ฌ
"kt", "skt", "lgt" ๋๋ null
currency_unit
์ฌํ ๋จ์
โPโ, โ์บ์โ, โ์โ, โMโ
won_to_currency_rate
์ํ ๊ธฐ์ค ํ์ฐ์จ
1
3.3 ์ต์
๋ ํ๋ผ๋ฏธํฐ(์ธ์ฝ๋ฉ ์ ์ฉ ์ํ ํ๋ผ๋ฏธํฐ)
custom
๋งค์ฒด์ฌ๋ณ custom data ํ๋
json ํ๋
custom2
๋งค์ฒด์ฌ๋ณ custom data ํ๋
json ํ๋
ย
4. ํ๋ผ๋ฏธํฐ ์ธ์ฝ๋ฉ ๊ณผ์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ์ค์ ์์์
๋๋ค.
JSON ๊ฐ์ฒด ์์ฑ
URI ์ธ์ฝ๋ฉ (JavaScript์ encodeURIComponent()
ํจ์ ์ฌ์ฉ)
Base64 ์ธ์ฝ๋ฉ (JavaScript์ btoa()
ํจ์ ์ฌ์ฉ)
ย
์์ JSON
{
"puid": "์ํธํ๋ ์ ์ ID",
"ifa": "a31752d2-5d7e-4f41-a45c-af4d39d2fb2d",
"birthday": "1990-01-01",
"year_of_birth": "1989",
"sex": "M",
"platform": "A",
"carrier": "kt",
"device_name": "SHV-E250S",
"region": "์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ"
}
'{"puid":"์ํธํ๋ ์ ์ ID","ifa":"a31752d2-5d7e-4f41-a45c-af4d39d2fb2d","birthday":"1990-01-01","year_of_birth":"1989","sex":"M","platform":"A","carrier":"kt","device_name":"SHV-E250S","region":"์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ"}'
URI ์ธ์ฝ๋ฉ let jsonString = '{"puid":"์ํธํ๋ ์ ์ ID","ifa":"a31752d2-5d7e-4f41-a45c-af4d39d2fb2d","birthday":"1990-01-01","year_of_birth":"1989","sex":"M","platform":"A","carrier":"kt","device_name":"SHV-E250S","region":"์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ"}';
let uriEncodedString = encodeURIComponent(jsonString);
Base64 ์ธ์ฝ๋ฉ let base64EncodedString = btoa(uriEncodedString);
์ต์ข
p๊ฐ ์์ฑ ์์์ ์ป์ Base64 ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด์ด ์ต์ข
์ ์ผ๋ก p ์ฟผ๋ฆฌ ๊ฐ์ด ๋ฉ๋๋ค. ์ด ๊ฐ์ URL์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ฃผ์
์ผ ํฉ๋๋ค.
https://ad.buzzvil.com/action/api/ads/uahub/buzzad?pquery=JTdCJTIyaWZhJTIyJTNBJTIyRVRFR0RHUkVHLTExQUFBLUJCQjIyMzQ1JTIyJTJDJTIyYWdlJTIyJTNBMzAlMkMlMjJzZXglMjIlM0ElMjJNJTIyJTJDJTIycGxhdGZvcm0lMjIlM0ElMjJBJTIyJTJDJTIyY2FycmllciUyMiUzQSUyMmt0JTIyJTJDJTIyZGV2aWNlX25hbWUlMjIlM0ElMjJTSFYtRTI1MFMlMjIlMkMlMjJyZWdpb24lMjIlM0ElMjIlRUMlODQlOUMlRUMlOUElQjglRUQlOEElQjklRUIlQjMlODQlRUMlOEIlOUMlMjAlRUElQjAlOTUlRUIlODIlQTglRUElQjUlQUMlMjIlN0Q=
2025.07.02 ๋๋,
https://ad.buzzvil.com/action/api/ads/uahub/buzzad?p=JTdCJTIyaWZhJTIyJTNBJTIyRVRFR0RHUkVHLTExQUFBLUJCQjIyMzQ1JTIyJTJDJTIyYWdlJTIyJTNBMzAlMkMlMjJzZXglMjIlM0ElMjJNJTIyJTJDJTIycGxhdGZvcm0lMjIlM0ElMjJBJTIyJTJDJTIyY2FycmllciUyMiUzQSUyMmt0JTIyJTJDJTIyZGV2aWNlX25hbWUlMjIlM0ElMjJTSFYtRTI1MFMlMjIlMkMlMjJyZWdpb24lMjIlM0ElMjIlRUMlODQlOUMlRUMlOUElQjglRUQlOEElQjklRUIlQjMlODQlRUMlOEIlOUMlMjAlRUElQjAlOTUlRUIlODIlQTglRUElQjUlQUMlMjIlN0Q=
5. ์ฃผ์์ฌํญ birthday
์ year_of_birth
์ค birthday
๊ฐ ์ฐ์ ์์๊ฐ ๋์ต๋๋ค. ์ ํํ ๋์ด ๊ณ์ฐ์ ์ํด ๊ฐ๋ฅํ birthday
๋ฅผ ์ฌ์ฉํ์ธ์.
๋ชจ๋ ์ ํ์ ํ๋ผ๋ฏธํฐ๋ ๊ฐ๋ฅํ ์ ๊ณตํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ ํ ํ๋ผ๋ฏธํฐ๊ฐ ์์ ๊ฒฝ์ฐ ํ ๋น ๋ฐ์ ์ ์๋ ๊ด๊ณ ๋ฌผ๋์ ์ ํ์ด ์๊น๋๋ค. ์๋ฅผ ๋ค์ด ์ฑ๋ณ ์ ๋ณด๋ฅผ ๋ณด๋ด์ฃผ์ง ์๋ ๊ฒฝ์ฐ ์ฑ๋ณ ํ๊ฒํ
๋ ๊ด๊ณ ๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค.
ย
6. ์ ๋ฆฝ ํฌ์คํธ๋ฐฑ ์ฐ๋ ์ฌ์ฉ์์๊ฒ ๋ณด์์ ์ง๊ธํ๊ธฐ ์ํด์ ํฌ์คํธ๋ฐฑ(Postback) ์ฐ๋์ด ํ์ํฉ๋๋ค. ํฌ์คํธ๋ฐฑ ์์ฒญ์ ๋ณด์์ ์ํด ์๋ฒ ๊ฐ ํต์ (Server-to-Server) ํํ๋ก ์งํ๋ฉ๋๋ค.
์ ์ฐจ ์์ฝ
๋ฒ์ฆ๋น์ ํฌ์ธํธ ์ ๋ฆฝ ์์ฒญ์ ๋ฐ์ ์ ์๋ ์๋ฒ endpoint ๊ตฌ์ถ (ํด๋น endpoint ์ URL์ postback url
๋ก ์ง์นญ)
๋ณธ ๊ฐ์ด๋์ ๋ฐ๋ผ Server-to-Server ์ฐ๋
๋ฒ์ฆ๋น ๊ธฐ์ ์ง์ ๋งค๋์ ์๊ฒ postback url ์ ๋ฌ
ย
Introduction ๋ฒ์ฆ๋น์ ํตํด ์ ์ ๊ฐ ํฌ์ธํธ๋ฅผ ์ง๊ธ๋ฐ์ ๊ฒฝ์ฐ, ๋งค์ฒด์ฌ์๊ฒ ์ด ์ฌ์ค์ ์ ๋ฌํ์ฌ ์ ๋ฆฝ ์์ฒญ์ ๋ณด๋ด๊ธฐ ์ํ API์
๋๋ค.
1 ์์ฒญ ๋ฐฉํฅ
๋ฒ์ฆ๋น โ ๋งค์ฒด์ฌ
2 HTTP Request method
POST - application/x-www-form-urlencoded
3 HTTP Request URL
๋งค์ฒด์ฌ ์๋ฒ์ endpoint
4 HTTP Request Parameters
์๋ Http Request Parameters
ํ
์ด๋ธ์ ์ฐธ๊ณ ํฉ๋๋ค.
5 HTTP Response Code
๋ฒ์ฆ๋น ์๋ฒ๋ ๋งค์ฒด์ฌ ์๋ฒ๋ก ๋ถํฐ ์ ๋ฌ๋ฐ์ ์๋ต ์ฝ๋(Response Code)๋ฅผ ๋ฐํ์ผ๋ก ์ ๋ฆฝ ์ฑ๊ณต ์ฌ๋ถ๋ฅผ ํ๋จํฉ๋๋ค.
200 (OK), 204 (No Content), 409 (Conflicted Request) : ์ฑ๊ณต ์ฒ๋ฆฌ
200, 204, 409 ์ด์ธ์ ์๋ต ์ฝ๋: ์ต๋ 5ํ๊น์ง ํด๋น Postback ์์ฒญ์ ์ฌ์๋
1๋ถ, 10๋ถ, 1์๊ฐ, 3์๊ฐ, 24์๊ฐ์ ๊ฐ๊ฒฉ์ ๋๊ณ ์ฌ์ ๋ฆฝ ์๋ ์ํ
200 ์ด์ธ์ ์๋ต ์ฝ๋๋ ํ์ค HTTP ์๋ต ์ฝ๋๋ฅผ ์ฐธ๊ณ ํฉ๋๋ค.
body์ ์ค๋ฅ ๋ด์ฉ์ ๋ด๋๋ผ๋ ์๋ต ์ฝ๋๊ฐ 200์ธ ๊ฒฝ์ฐ ์ฌ์๋ํ์ง ์์ผ๋ฏ๋ก ์ฃผ์ํด ์ฃผ์ธ์.
HTTP Request Parameters ๊ธฐ๋ฅ์ ๋ฐ๋ผ์ ๋ ์ข
๋ฅ์ ํฌ์คํธ๋ฐฑ์ด ์กด์ฌํฉ๋๋ค. ๊ฐ ํ์
์ ๊ดํ ํฌ์คํธ๋ฐฑ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ ์๋์ ํ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
String ํ์
์ ํ๋ผ๋ฏธํฐ ํ๋ ๊ฐ์ด ํ๊ตญ์ด์ผ ๊ฒฝ์ฐ์๋ ์ ๋์ฝ๋๋ก ์ธ์ฝ๋ฉ๋์ด ์ ๋ฌ๋ฉ๋๋ค.
ํ๋ผ๋ฏธํฐ ํ๋(Field)
ํ๋ผ๋ฏธํฐ ํ๋(Field)
user_id
REQUIRED
Stringย (max 65)
๋งค์ฒด์ฌ์์ ์ ์ํ ์ ์ ์ ์๋ณ๊ฐ
์ต๋ 65์ ๊น์ง๋ง ์ ๋ฌ ๊ฐ๋ฅํฉ๋๋ค.
transaction_id
REQUIRED
Stringย (max 32)
๋ณด์์ ๋ฐ๊ธ๋๋ ID. ๊ฐ ๋ณด์์ ์๋ณํ๊ณ ํฌ์ธํธ ์ค๋ณต ์ง๊ธ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ฌ์ฉ
์ฌ์ ๋ฆฝ ์๋ ์ ๋์ผํ transaction_id
๋ก ํฌ์คํธ๋ฐฑ์ ์์ฒญํฉ๋๋ค.
๊ฐ์ transaction_id
๋ก ์์ฒญ์ด ์จ ๊ฒฝ์ฐ์ ํฌ์ธํธ๊ฐ ์ค๋ณต ์ ๋ฆฝ๋์ง๋ ์๋์ง ํ์์ ์ผ๋ก ์ ์ํด์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
point
REQUIRED
Integer
์ ์ ์๊ฒ ์ง๊ธํด์ผํ๋ ํฌ์ธํธ
unit_id
REQUIRED
Long
๊ด๊ณ ๊ฐ ๋
ธ์ถ๋ ์ง๋ฉด์ ID ๊ฐ
ํ์ฌ ์ฃผ๋ก ์ฌ์ฉํ๋ ๊ฐ์ 15์๋ฆฌ์ ์ซ์์
๋๋ค.
title
REQUIRED
String (max 255)
ํฌ์ธํธ๊ฐ ์ง๊ธ๋ ๋ฐฉ์์ ์ค์ ๋ ์ด๋ฆ
์ต๋ ํ๊ธ 255์ ๊น์ง ์ ๋ฌ๋ ์ ์์ผ๋ฏ๋ก ์ฐ๋ ์ DB๋ณ String ์ฌ์ด์ฆ๋ฅผ ์ฐธ์กฐํด ์ฃผ์ธ์.
event_at
REQUIRED
Long (timestamp)
ํฌ์ธํธ ์ง๊ธ ์์ (UNIX Timestamp ์ด๋จ์)
๋๋ถ๋ถ API ํธ์ถ์์ ๊ณผ ๋์ผํ์ง๋ง API ํธ์ถ์ด ์ฌ์๋์ธ ๊ฒฝ์ฐ ๋ค๋ฅผ ์ ์์ต๋๋ค.
action_type
OPTIONAL
String (max 32)
ํฌ์ธํธ๋ฅผ ์ง๊ธ ๋ฐ๊ธฐ ์ํด ์ ์ ๊ฐ ์ทจํ ์ก์
ํ์
opened
: Feed ์ง๋ฉด ์ง์
(์ง๋ฉด์ ๋ฐฉ๋ฌธํ๊ธฐ๋ง ํด๋ ๊ธฐ๋ณธ ๋ฆฌ์๋ ์ ๋ฆฝ)
u
: ์ ๊ธ ํด์
l
: ๋๋ฉ
a
: ์ก์
(ํด๋น ๊ด๊ณ ์ ์๊ตฌ ์ก์
์ ์๋ฃํ์ ๋)
p
: ์ปจํ
์ธ ์ฐธ์ฌ
won
: Potto์์ ๋น์ฒจ๋ฒํธ์ ๋น์ฒจ๋์์ ์ ํฌ์ธํธ ์ ๋ฆฝ์ ์์ฒญ
manual
: ๋ด๋น์ ์๊ธฐ ์ ๋ฆฝ ์์ฒญ
spinned
: ๋ฃฐ๋ ๋ฏธ์
์ฐธ์ฌ ์ ์ง๊ธ๋๋ ํฌ์ธํธ
daily
: Feed ์ถ์์ฒดํฌ(๋ฐ์ผ๋ฆฌ ๋ฆฌ์๋ ์ด๋ฒคํธ) ์ฐธ์ฌ ๋ณด์
benefit_luckybox
: ๋ญํค๋ฐ์ค ์ฐธ์ฌ ๋ณด์
benefit_missionpack
: ๋ฏธ์
ํฉ ํน๋ณ ๋ณด์
benefit_missionpack_task
: ๋ฏธ์
ํฉ ๋ฏธ์
๋ณ ๋ณด์
๋ฒ์ฆ๋ถ์คํฐ๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
booster_attended
: ๋ฒ์ฆ๋ถ์คํฐ ์ถ์์ฒดํฌ ๋ณด์
booster_hiddendone
: ๋ฒ์ฆ๋ถ์คํฐ ๋น๋
ธ์ถ ์บ ํ์ธ ๋ณด์
booster_optedin
: ๋ฒ์ฆ๋ถ์คํฐ ๋ง์ผํ
์์ ๋์ ์บ ํ์ธ ๋ณด์
booster_spinned
: ๋ฒ์ฆ๋ถ์คํฐ ๋ฃฐ๋ ์บ ํ์ธ ๋ณด์
booster_scratched
: ๋ฒ์ฆ๋ถ์คํฐ ๊ธ๋ ๋ณต๊ถ ์บ ํ์ธ ๋ณด์
booster_stamped
: ๋ฒ์ฆ๋ถ์คํฐ ์คํ
ํ ์บ ํ์ธ ๋ณด์
booster_inviting
: ์น๊ตฌ ์ด๋ ์บ ํ์ธ ๋ณด์ (์ด๋ ํ ์ฌ๋)
booster_invited
: ์น๊ตฌ ์ด๋ ์บ ํ์ธ ๋ณด์ (์ด๋ ๋ฐ์ ์ฌ๋)
์ถํ ๋ค์ํ action_type
์ด ํ์
์ด ์ถ๊ฐ๋ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ํฌ์คํธ๋ฐฑ ์์ฒญ์ ๋ฐ์ ๋ ์ ์๋ ๊ฐ๋ง ๋ฐ๋๋ก ํ๋ ๊ฒ์ด ์๋, ๊ฐ์ ๊ตฌ์ ๋ฐ์ง ์๊ณ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๋๋ก ์ ์ ๋ฐ๋๋๋ค.
revenue_type
OPTIONAL
String (max 32)
์ ์ ๊ฐ ์ฐธ์ฌํ ๊ด๊ณ ์ ๊ด๊ณ ์ ํ
๋ชจ๋ ๊ด๊ณ ์ ํ ๋ฆฌ์คํธ
cpc
: ํด๋ฆญํ ์ํ
cpm
: ๋
ธ์ถํ ์ํ
cpa
: ์ผ๋ฐ ์ฐธ์ฌํ ์ํ
cpk
: ์นด์นด์คํก ์ฑ๋ ์ถ๊ฐ ์ํ
cpq
: ํด์ฆ ์ํ
cpqlite
: ํด์ฆ ์ํ
cpl
: ํ์ด์ค๋ถ ์ข์์ ์ํ
cpyoutube
: ์ ํ๋ธ ๊ตฌ๋
์ํ
cps
: ์ผํํ ์ํ
cptiktok
: ํฑํก ํ๋ก์ฐ ์ํ
cpnstore
: ๋ค์ด๋ฒ ์คํ ์ด ์๋ฆผ์ค์ ์ํ
cpi
: ์ฑ ์ค์น ์ํ
cpe
: ์ฑ๋ด ์ด๋ฒคํธ ์ฐธ์ฌ ์ํ
cpylike
: ์ ํ๋ธ ๊ตฌ๋
+์ข์์ ์ํ
cpinsta
: ์ธ์คํ๊ทธ๋จ ํ๋ก์ฐ ์ํ
cpcquiz
: ํด์ฆ ์ ๋ฆฝ ์ปจํ
์ธ
์ถํ ๋ค์ํ ํ์
์ด ์ถ๊ฐ๋ ์ ์์ต๋๋ค.
extra
OPTIONAL
String (max 1024)
ํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํด์ผํ ๊ฒฝ์ฐ, ํด๋น ํ๋ผ๋ฏธํฐ(JSON serialize ๋ ๋ฌธ์์ด ๊ฐ)๋ฅผ ํ์ฉ
ํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์ผ์๋ค๋ฉด help@buzzvil.com์ผ๋ก ๋ฌธ์ ๋ถํ๋๋ฆฝ๋๋ค.
campaign_id
OPTIONAL
Long
์ ์ ๊ฐ ์ฐธ์ฌํ ์บ ํ์ธ(๊ด๊ณ , ์ปจํ
์ธ , ํ๋ก๋ชจ์
) ์ ID์
๋๋ค.
data
OPTIONAL
String
HTTP request parameter๋ฅผ ์ํธํ ํด์ ์ ์กํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ๋๋ ํ๋ผ๋ฏธํฐ
์์ธํ ๋ด์ฉ์ ์๋ HTTP Request Parameter Encryption/Decryption์ ์ฐธ์กฐํ์ธ์.
c
OPTIONAL
String
HTTP request parameter์ Checksum์ ์ ์กํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ๋๋ ํ๋ผ๋ฏธํฐ
์์ธํ ๋ด์ฉ์ ์๋ Add Checksum Parameter๋ฅผ ์ฐธ์กฐํ์ธ์.
custom2
OPTIONAL
String (max 255)
ํผ๋ธ๋ฆฌ์
์ค์๊ฐ S2S API ์ ํ ์ฐ๋ ๋งค์ฒด์ฌ์์ ์ง์ ํ๋ ์ปค์คํ
ํ๋ผ๋ฏธํฐ
custom3
OPTIONAL
String (max 255)
ํผ๋ธ๋ฆฌ์
์ค์๊ฐ S2S API ์ ํ ์ฐ๋ ๋งค์ฒด์ฌ์์ ์ง์ ํ๋ ์ปค์คํ
ํ๋ผ๋ฏธํฐ
custom4
OPTIONAL
String (max 255)
ํผ๋ธ๋ฆฌ์
์ค์๊ฐ S2S API ์ ํ ์ฐ๋ ๋งค์ฒด์ฌ์์ ์ง์ ํ๋ ์ปค์คํ
ํ๋ผ๋ฏธํฐ
ย
HTTP Request Parameter ํฌ์คํธ๋ฐฑ ์์ ๋ค์์ HTTP Request Parameter์ ํฌ์คํธ๋ฐฑ ์์ ์
๋๋ค.
{
"user_id": "12345",
"point": 1,
"transaction_id": "126905422_10000001",
"event_at": 1641452397,
"unit_id": 5539189976900000,
"action_type": "l",
"title": "ํ์ดํ",
"extra": "{}"
}
ย
IP Whitelist ์ถ๊ฐ ๋ฒ์ฆ๋น ์๋ฒ์์ ๋ณด๋ด๋ ํฌ์ธํธ ์ ๋ฆฝ ์์ฒญ์ ๋ฐ์ ์ ์๋๋ก ์๋ IP์ ๋ํ inbound ๋ฐฉํ๋ฒฝ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ถํ ๋๋ฆฝ๋๋ค.
13.231.21.93
18.179.158.39
52.68.114.43
์์ฒญ ํ๋ผ๋ฏธํฐ ๊ฒ์ฆย OPTIONAL ๋ฒ์ฆ๋น ์๋ฒ์์ ์ ๋ฌ๋๋ ํฌ์ธํธ ์ ๋ฆฝ ์์ฒญ(ํฌ์คํธ๋ฐฑ)์ ์ํธํ ํ ์ ์์ต๋๋ค. ์ด ๊ณผ์ ์ ํ์ ์ ์ฉ ํญ๋ชฉ์ ์๋๋ฉฐ, ํ์ํ ๊ฒฝ์ฐ ์๋์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
1. HTTP Request Parameter Encryption/Decryption ๋ฒ์ฆ๋น ์๋ฒ์์ ๋งค์ฒด์ฌ๋ก ๋ณด๋ด๋ HTTP Request parameter๋ฅผ ์ํธํ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ ์ฌ์ฉํฉ๋๋ค. ์ ๊ณตํ๋ ์ํธํ ๋ฐฉ์์ ๊ณ ๊ธ ์ํธํ ํ์ค, AES (Advanded Encryption Standard)์
๋๋ค. ์ ๊ณต๋๋ ๋ธ๋ก ์ํธํ๋ AES-256
์ด๊ณ , ์ฌ์ฉํ๋ ๋ธ๋ก ์ํธํ ๋ชจ๋(Block Cipher)๋ CBC(Cipher Block Chaning) Mode์ PKCS7์ ์ฌ์ฉํฉ๋๋ค.
์งํ ๊ณผ์
์ค๋น๋ฌผ
๋ฒ์ฆ๋น ๋งค๋์ ํตํด AES-256
์ํธํ์ ํ์ํ ์๋ ๊ฐ ๋ฐ๊ธ:
AES Key (๊ธธ์ด 32)
AES IV (๊ธธ์ด 16)
๋ฒ์ฆ๋น โ ๋งค์ฒด์ฌ๋ก AES Key, IV ๊ฐ์ ์ ๋ฌํ๊ธฐ ์ , ๋งค์ฒด์ฌ์์ RSA-1024
๋ก private key์ public key๋ฅผ ๋ฐ๊ธํ๊ณ public key ๋ฅผ ๋ฒ์ฆ๋น ๋งค๋์ ์๊ฒ ์ ๋ฌ
์งํ ์ ์ฐจ
๋ฒ์ฆ๋น ์๋ฒ์์ HTTP Request parameter๋ฅผ ์ํธํ
JSON serialized parameters(string)์ ํด๋น string์ UTF-8
์ธ์ฝ๋ฉ ์ ์ฉ
ํด๋น string์ PKCS7
ํจ๋ฉ ์ ์ฉ ๋ฐ AES ์ํธํ ์งํ
์ํธํ๋ ๊ฐ์ base64
encoding์ ์งํ
์ํธํ ๋ ๋ฐ์ดํฐ๋ฅผ HTTP POST request์ ํ๋ผ๋ฏธํฐ data
๋ผ๋ ์ด๋ฆ์ผ๋ก ์ถ๊ฐํ์ฌ ์ ์ก
e.g
{
"data": "cg087LiIp30jCWpc3MVLfxPL4F05OFGGCkQwwpS6pRVMZhkumzfTFxc8iBoZ8unI15uk0cmY+CbSeOaLHsd7PaxsbyKISiJ31WJJ1OwfaYttoMwFysKNfL7pSz2HB9ULWZicG8MSPxCPKr9RDqgOXpuEoVm9YR3I4yNE5M0LNltpCTdXRBjTrOcjp+RtEZ1VENtHqTICK18nDqO+91BUt3AJsf4VmzogJ8UpA0izEbY="
}
์์ ์ธก (๋งค์ฒด์ฌ) ์์๋ HTTP POST request์์ data
ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ ธ์ ์๋์ ๊ฐ์ ์์๋ก ๋ณตํธํ
์ํธํ๋ ๊ฐ์ base64
decoding ์งํ
ํด๋น decoding๋ string์ ๋ณตํธํ ์งํ ์ดํ PKCS7
ํจ๋ฉ ์ ๊ฑฐ
ํด๋น string์ UTF-8
๋์ฝ๋ฉ
ย
์์ {
"unit_id":"12345",
"transaction_id":"10000000_1",
"user_id":"buzzvil",
"point": 1,
"action_type":"won",
"event_at": 1599622182,
"title":"title",
"extra": "{}"
}
ย
Java 1.8+
import java.lang.RuntimeException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.*;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) {
String aesKey = "BuzzvilAESKeyTest123456789101112";
String aesIV = "0000000000000000";
// Check to make sure encryption is compatible with Buzzvil
String toBuzzvilMessage = "{\"success\": 1, \"reason\": \"์ค๋ณต ์ ๋ฆฝ ์์ฒญ\"}";
String encrypted = encrypt(toBuzzvilMessage, aesKey, aesIV);
System.out.println("----encrypted----\n"+encrypted);
System.out.println("buzzvil encryption compatible? YES");
// Check to make sure values coming from Buzzvil is decryptable
String fromBuzzvilEncrypted = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw==";
String fromBuzzvilDecrypted = "{\"point\": 1, \"user_id\": \"buzzvil_test\", \"transaction_id\": \"100004_100000000\", \"event_at\": 1588936508, \"campaign_name\": \"๋ฒ์ฆ๋น ํ
์คํธ campaign_name\", \"extra\": \"{}\", \"action_type\": \"l\", \"base_point\": 1, \"campaign_id\": 202010160022, \"is_media\": 1, \"unit_id\": 452613281179508, \"revenue_type\": \"cpm\"}";
String decrypted = decrypt(fromBuzzvilEncrypted, aesKey, aesIV);
System.out.println("----decrypted-----\n"+decrypted);
System.out.println("buzzvil decryption compatible? "+fromBuzzvilDecrypted.equals(decrypted));
}
static String encrypt(String message, String key, String iv) {
try {
// 1. encode in utf-8
byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
// 2. encrypt message through AES CBC with PKCS7
byte[] encrypted = aes(messageBytes, key, iv, Cipher.ENCRYPT_MODE);
// 3. encode in base64
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
}
static String decrypt(String message, String key, String iv) {
try {
// 1. decode base64 message
byte[] base64DecodedBytes = Base64.getDecoder().decode(message);
// 2. decrypt message through AES CBC with PKCS7
byte[] decrypted = aes(base64DecodedBytes, key, iv, Cipher.DECRYPT_MODE);
// 3. decode in utf-8
return new String(decrypted, StandardCharsets.UTF_8);
} catch (Exception e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
}
static byte[] aes(byte[] messageBytes, String key, String iv, int cipherMode) {
try {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(cipherMode, keySpec, ivSpec);
return cipher.doFinal(messageBytes);
} catch (Exception e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
}
}
PHP 7.0+
<?php
function encrypt($str, $mode, $key, $iv) {
$encrypted = openssl_encrypt($str, $mode, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($encrypted);
}
function decrypt($str, $mode, $key, $iv) {
$text = base64_decode($str);
return openssl_decrypt($text, $mode, $key, OPENSSL_RAW_DATA, $iv);
}
$mode = "AES-256-CBC";
$key = "BuzzvilAESKeyTest123456789101112";
$iv = "0000000000000000";
$plaintext = '{"success": 1, "reason": "์ค๋ณต ์ ๋ฆฝ ์์ฒญ"}';
$encrypted = encrypt($plaintext, $mode, $key, $iv);
print ("ENCRYPTED: ".$encrypted."\n");
// +VEmHrt+jwI6Dg2zImdGtI+iIQEqV8v5btpS1a3cdEQBzIc72V9aKju5m6+ELTBixbITMBoHIYjj8jJbsKbIgg==
$fromBuzzvil = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw==";
$decrypted = decrypt($fromBuzzvil, $mode, $key, $iv);
print("DECRYPTED: ".$decrypted);
/*
{"point": 1, "user_id": "buzzvil_test", "transaction_id": "100004_100000000", "event_at": 1588936508, "campaign_name": "๋ฒ์ฆ๋น ํ
์คํธ campaign_name", "extra": "{}", "action_type": "l", "base_point": 1, "campaign_id": 202010160022, "is_media": 1, "unit_id": 452613281179508, "revenue_type": "cpm"}
*/
?>
Python 2.7+ & Python 3.6+
Python 2.7+
# -*- coding:utf-8 -*-
import base64
# https://pypi.python.org/pypi/pycryptodome/3.9.9
from Crypto.Cipher import AES
# https://pypi.python.org/pypi/pkcs7/0.1.2
from pkcs7 import PKCS7Encoder
def encrypt(message, key, iv):
message_plaintext_padded = PKCS7Encoder().encode(message)
cipher = AES.new(key, AES.MODE_CBC, iv)
message_encrypted_raw = cipher.encrypt(message_plaintext_padded)
return base64.b64encode(message_encrypted_raw)
def decrypt(message, key, iv):
message_decoded = base64.b64decode(message)
cipher = AES.new(key, AES.MODE_CBC, iv)
messaged_decrypted_padded = cipher.decrypt(message_decoded)
message_plaintext_decoded = PKCS7Encoder().decode(messaged_decrypted_padded)
return message_plaintext_decoded
iv = '0000000000000000'
key = 'BuzzvilAESKeyTest123456789101112'
plaintext = '{"success": 1, "reason": "์ค๋ณต ์ ๋ฆฝ ์์ฒญ"}'
encrypted = encrypt(plaintext, key, iv)
print "ENCRYPTED: {}".format(encrypted)
# +VEmHrt+jwI6Dg2zImdGtI+iIQEqV8v5btpS1a3cdEQBzIc72V9aKju5m6+ELTBixbITMBoHIYjj8jJbsKbIgg==
from_buzzvil = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw=="
decrypted = decrypt(from_buzzvil, key, iv)
print "DECRYPTED: {}".format(decrypted)
#{"point": 1, "user_id": "buzzvil_test", "transaction_id": "100004_100000000", "event_at": 1588936508, "campaign_name": "๋ฒ์ฆ๋น ํ
์คํธ campaign_name", "extra": "{}", "action_type": "l", "base_point": 1, "campaign_id": 202010160022, "is_media": 1, "unit_id": 452613281179508, "revenue_type": "cpm"}
ย
Python 3.6+
# -*- coding:utf-8 -*-
import base64
# https://pypi.python.org/pypi/pycryptodome/3.9.9
from Crypto.Cipher import AES
from binascii import unhexlify
BLOCK_SIZE = 16
def encrypt(message, key, iv):
message_plaintext_padded = pad(message).encode('utf-8')
cipher = AES.new(key, AES.MODE_CBC, iv)
message_encrypted_raw = cipher.encrypt(message_plaintext_padded)
return base64.b64encode(message_encrypted_raw)
def decrypt(message, key, iv):
message_decoded = base64.b64decode(message)
cipher = AES.new(key, AES.MODE_CBC, iv)
messaged_decrypted_padded = unpad(cipher.decrypt(message_decoded))
return messaged_decrypted_padded.decode('utf-8')
def pad(s):
return s + (BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE)
def unpad(s):
return s[:-ord(s[len(s)-1:])]
iv = '0000000000000000'.encode('utf-8')
key = 'BuzzvilAESKeyTest123456789101112'.encode('utf-8')
plaintext = '{"success": 1, "reason": "์ค๋ณต ์ ๋ฆฝ ์์ฒญ"}'
encrypted = encrypt(plaintext, key, iv)
print ("ENCRYPTED: {}".format(encrypted))
# +VEmHrt+jwI6Dg2zImdGtI+iIQEqV8v5btpS1a3cdEQBzIc72V9aKju5m6+ELTBixbITMBoHIYjj8jJbsKbIgg==
from_buzzvil = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw=="
decrypted = decrypt(from_buzzvil, key, iv)
print ("DECRYPTED: {}".format(decrypted))
#{"point": 1, "user_id": "buzzvil_test", "transaction_id": "100004_100000000", "event_at": 1588936508, "campaign_name": "๋ฒ์ฆ๋น ํ
์คํธ campaign_name", "extra": "{}", "action_type": "l", "base_point": 1, "campaign_id": 202010160022, "is_media": 1, "unit_id": 452613281179508, "revenue_type": "cpm"}
ย
2. Add Checksum Parameter ํฌ์คํธ๋ฐฑ ๋ฐ์ดํฐ ๊ฒ์ฆ์ ์ํด Request Parameter์ Checksum parameter๋ฅผ ์ถ๊ฐํ๊ณ ์ ํ๋ ๊ฒฝ์ฐ ์ฌ์ฉํฉ๋๋ค. ์ ๊ณตํ๋ ๋ฐ์ดํฐ ๊ฒ์ฆ ๋ฐฉ์์ HMAC ์ธ์ฆ์ด๊ณ , SHA-256
์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํฉ๋๋ค.
์งํ ๊ณผ์
์ค๋น๋ฌผ
์งํ ์ ์ฐจ
์ ๋ฌ๋ฐ์ ํฌ์คํธ๋ฐฑ ํ๋ผ๋ฏธํฐ ์ค transaction_id
, user_id
, point
, event_at
๊ฐ์ผ๋ก ์๋ ํ์๋๋ก String์ ์์ฑ (์ดํ "msg"
)
์ฃผ์์ฌํญ : msg
๊ฐ์ ์ธ์ฝ๋ฉ๋์ด์ผ ํ๋ฉฐ, ๊ฐ ํ๋ผ๋ฏธํฐ string ๊ณผ colon ์ฌ์ด์๋ ๋์ด์ฐ๊ธฐ๊ฐ ์์ต๋๋ค.
msg=u'{0}:{1}:{2}:{3}'.format(
params['transaction_id'],
params['user_id'],
params['point'],
params['event_at'],
).encode('utf-8')
ย
HMAC SHA-256 ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ msg
๊ฐ์ ์ํธํ
์ ๋ฌ๋ฐ์ ํฌ์คํธ๋ฐฑ ํ๋ผ๋ฏธํฐ ์ค c
ํ๋์ ๊ฐ๊ณผ ๋น๊ต, ์ผ์น ์ฌ๋ถ๋ฅผ ํ์ธ
์์ ๋งค์ฒด์ฌ ํฌ์ธํธ ์ ๋ฆฝ ํฌ์คํธ๋ฐฑ API ์ฐ๋
ย
7. ์ง์ ๋ฐ ๋ฌธ์ ์ฐ๋ ๊ณผ์ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฑฐ๋ ์ถ๊ฐ ์ ๋ณด๊ฐ ํ์ํ ๊ฒฝ์ฐ, Buzzvil ๊ธฐ์ ์ง์ํ์ ๋ฌธ์ํด ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
csm@buzzvil.com