Аюулгүй байдлын checklist¶
Live болохоос өмнө, дараа нь улирал бүр энэ жагсаалтаар интеграцаа шалгана. Хугацаа: 30 минут. Хэрэгтэй: таны backend-ийн код, тохиргоо ба консолын хандалт. Загварын тайлбар: Аюулгүй байдлын загвар.
Secret хадгалалт¶
- API түлхүүрийн secret (
gks_live_…,gks_test_…; хуучин анхдагч түлхүүрийнgma_cs_…) ба webhook secret (whsec_…) зөвхөн сервер дээр — орчны хувьсагч эсвэл secret manager-т. Мобайл апп, браузер, JavaScript, терминал, вендинг машин, POS, kiosk дотор хэзээ ч: тэд таны backend-ийг дуудна, таны backend Gerege-ийг. - Secret git репод, Docker image-д, log-д, алдааны мессежид, analytics-д ороогүй (
.envнь.gitignore-д). Client id (gk_…,mapp_…) нууц биш — log-д бичиж болно. - Mini app-ын access ба refresh token (
gma_at_…,gma_rt_…) зөвхөн backend-д; frontend-д өөрийн session cookie л. - Test ба live түлхүүр тусдаа хадгалагдсан; live secret-ийг хэрэгтэй хүн л харна.
Түлхүүр — хамгийн бага эрх, солих, хүчингүй болгох¶
- Сервер бүрт тусдаа, нэртэй түлхүүр («checkout-api», «bi-readonly») — нэг нь алдагдвал зөвхөн түүнийг зогсооно. Апп дотор орчин бүрт идэвхтэй ≤ 20.
- Хамгийн бага scope: preset-ээс эхэлнэ —
checkout_server(payments:read,payments:write,refunds:write,events:read),read_only(BI, нягтлан),terminal_installer… Scope-ыг дараа нь өөрчлөхгүй (400 scopes_immutable) — өөр эрх бол шинэ түлхүүр. Дутуу бол403 insufficient_scope+required_scope. - Солих (roll):
POST /api/v1/miniapp/dev/apps/{id}/keys/{kid}/roll{"overlap_seconds": …}— ижил нэр, scope-той шинэ secret; хуучин нь давхцлын хугацаанд (0 – 7 хоног, анхдагч 24 цаг) ажилласаар. Тэр хугацаанд шинийг deploy хийнэ — тасалдалгүй.expires_atөгсөн түлхүүрийн хугацаа дуусахаас өмнө үүсгэсэн хүн ба админууд мэдэгдэл авна. - Live түлхүүр: үүсгэх, солих, IP өөрчлөх нь
miniapp.keys.liveба сүүлийн 10 минутын нэвтрэлт шаардана (403 fresh_sign_in_required→ дахин нэвтэрч давтана). Анхдагч түлхүүрийн live secret (POST …/credentials{"environment": "live"}) ч мөн адил; тэр солилт шууд, давхцалгүй — deploy-оо урьдчилан бэлдэнэ, эсвэл шинэ API-ын roll-ыг (давхцалтай) хэрэглэнэ. Live түлхүүрийн үүсгэлт, солилт, хүчингүй болголт байгууллагын админуудад мэдэгдэл болно. - Хүчингүй болгох:
POST …/keys/{kid}/revoke{"reason": "…"}(шалтгаан заавал, ≤ 200) — шууд, дахин нэвтрэлт шаардахгүй (хамгаалах үйлдлийг хэзээ ч удаашруулахгүй). Хүчингүй, хугацаа дууссан, солигдсон түлхүүр бүгд адилхан401 invalid_client. - IP allowlist (
allowed_ips, ≤ 20 хаяг/CIDR): live server-ийнхээ гарах хаягийг тавина — бусад хаягаас403 ip_not_allowed(ip— платформын харсан хаяг, итгэмжлэгдсэн proxy-ийн ард). Live түлхүүрийн allowlist-ийг өөрчлөх нь дахин нэвтрэлт шаардана. - Webhook secret: endpoint-ийн
POST …/webhook-endpoints/{eid}/rotate-secret— шинэwhsec_…, хуучин нь 24 цаг хамт гарын үсэг зурна (хоёрv1). Тэр хугацаанд handler[шинэ, хуучин]хоёуланг зөвшөөрнө, дараа нь хуучныг хасна. Endpoint №1-д (POST …/webhook{"url"}) дуудлага бүр шинэ secret олгоно.
Webhook¶
- Event бүрийн гарын үсгийг түүхий body-оор (JSON parse хийхээс өмнө), constant-time харьцуулалтаар, бүх
v1-ийг шалгана;|now − t| ≤ 300секунд (Гарын үсэг шалгах). - Гарын үсэггүй, буруу гарын үсэгтэй хүсэлтийг
400-аар татгалзаж, юу ч хийхгүй. -
Gerege-Event-Id-аар давхардлыг арилгана; бараа олгохоос өмнө intent-ийг API-аас дахин уншина (Idempotent handler). - Endpoint нь
https://, нийтийн хаяг; test ба live-д тусдаа endpoint (өөр secret); нийтийн «request bin»-д live event хэзээ ч.
Төлбөрийг шалгах¶
- Дүн үргэлж таны серверээс. Intent-ийг таны backend өөрийн захиалгын дүнгээр үүсгэнэ; дүн, тайлбарыг браузер, апп, машинаас ирсэн утгаар хэзээ ч.
-
return_url?pi=…-д итгэхгүй. Redirect checkout-ын дараа хүн таны хуудсанд?pi=pi_…-тэй буцна — үүнийг хэн ч гараар бичиж болно. Серверээсээ өөрийн түлхүүрээрGET /payment-intents/{id}хийжstatus(succeeded/requires_capture),amount,reference,livemode-ыг захиалгатайгаа тулгана. - Mini app-ын bridge-ийн
requestPaymentхариу, Gerege App-ын дэлгэц, URL — аль нь ч төлбөрийн нотолгоо биш; нотолгоо нь таны backend-ийнGETэсвэл гарын үсэг шалгасан webhook. - Нэг захиалга = нэг intent = нэг
Idempotency-Key(захиалгын дугаар). Давталт ижил key-ээр — шинэ key давхар төлбөр үүсгэнэ (Давталт).
Терминал ба sticker¶
- Терминал, sticker, NFC tag, QR secret барихгүй — зөвхөн терминалын URL. Машин таны backend-ээс сагсаа асууна.
- NFC tag бүрийг бичсний дараа түгжинэ (Gerege App-ын «Sticker бичих» шалгаад түгждэг); sticker-ийг хуурамчаар дээгүүр нь наасан эсэхийг тогтмол шалгана (NFC-г турших).
- Терминалын
label,location-ийг тодорхой бичнэ — Gerege App-ын төлөх цонх Face ID-аас өмнө бүртгэлтэй нэр, байршлыг харуулдаг тул хүн буруу машиныг танина. - Хүн явчихсан claim-ийг
POST /payment-intents/{id}/unclaim-аар суллана; баталгаажаагүй claim 90 секундэд өөрөө дуусна, нэг хүн нэг дор 3-аас олон баталгаажаагүй claim барихгүй. - Терминал бүртгэх, засах түлхүүр (
terminals:write) нь машин дээр биш, таны сервер дээр; суулгагчидterminal_installerpreset-тэй тусдаа түлхүүр. - Уншилт бүрт гарын үсэгтэй URL (NTAG 424 DNA, SUN) — «удахгүй».
Хүнд харагдах текст¶
-
description(≤ 80 тэмдэгт) хүний төлөх цонхонд гарна — захиалгын товч («Захиалга #8812», «Ус 0.5л»). URL, утасны дугаар, «нууц код», «баталгаажуулах код илгээ» мэт хэллэг хэзээ ч. - Тамхи, согтууруулах ундааны бүтээгдэхүүний нэр
description-д бичихгүй (App Store-ийн дүрэм 1.4.3); насны шалгалт машин/таны талд, эсвэлmin_age. - Буцаалтын
reasonтаны API ба webhook-д л харагдана, хүний мэдэгдэлд биш — гэхдээ хувийн мэдээлэл бүү бич.
Хувийн мэдээлэл¶
- Худалдагч хүний нэр, регистр, данс, утсыг хэзээ ч авахгүй.
user_refнь claim бүрт санамсаргүй — нэг хүнийг төлбөр хооронд холбох тогтвортой id биш (Хүний мэдээлэл). - Mini app хүний pairwise
sub-ийг (апп бүрт өөр) ба зөвхөн зөвшөөрсөн scope-ийн мэдээллийг (profile.email,profile.phone) авна (Mini app-ын нээлт ба token). - Авсан мэдээллээ хуулийн дагуу хадгалж, нууцлалын бодлогодоо тодорхой бичнэ; шаардлагагүй болсныг устгана.
Secret илрүүлэх¶
Угтварууд нь scanner-т зориулагдсан: gks_live_ / gks_test_ (API түлхүүрийн secret — сүүлдээ 6 тэмдэгт CRC32
checksum-тай тул DB-гүйгээр жинхэнэ хэлбэрийг шүүнэ), gma_cs_ (анхдагч түлхүүрийн secret), whsec_ (webhook secret),
gml_ (launch code), gma_at_ (access token), gma_rt_ (refresh token). Client id (gk_live_ / gk_test_ + 20
тэмдэгт, mapp_ / mapp_test_) нь нууц биш. Жишээ нь gitleaks-ийн дүрэм:
[[rules]]
id = "gerege-api-key-secret"
description = "Gerege App API key secret"
regex = '''gks_(live|test)_[A-Za-z0-9_-]{43}_[0-9A-Za-z]{6}'''
[[rules]]
id = "gerege-client-secret"
description = "Gerege App default key secret"
regex = '''gma_cs_[A-Za-z0-9_-]{43}'''
[[rules]]
id = "gerege-webhook-secret"
description = "Gerege App webhook secret"
regex = '''whsec_[A-Za-z0-9_-]{43}'''
[[rules]]
id = "gerege-token"
description = "Gerege App access / refresh token"
regex = '''gma_(at|rt)_[A-Za-z0-9_-]{43}'''
Secret алдагдвал¶
- Тэр дор нь зогсооно — API түлхүүр:
POST …/keys/{kid}/revoke(шууд); анхдагч түлхүүр:POST …/credentials(хуучин шууд үхнэ); webhook secret:rotate-secret(хуучин 24 цаг хамт ажиллана — алдагдсан бол handler-аасаа хуучныг шууд хас). - Шинэ secret-ийг deploy хийнэ.
- Консолын audit-аас (
key_created,key_rolled,key_revoked,credentials_rotated, endpoint-ийн өөрчлөлт …) хэн юу хийснийг, түлхүүрийнlast_used_at-ийг, төлбөр/буцаалтын жагсаалтаас танихгүй үйлдлийг шалгана. - Тусламж-тай холбогдоно — secret-ийг өөрийг нь хэзээ ч бүү илгээ.