ALTCHA Anti-Bot (Proof-of-Work) — มาตรฐานกลางสำหรับแบบฟอร์มสาธารณะ¶
สถานะ (12 ส.ค. 2569): ใช้งานจริงครบทุกแบบฟอร์มสาธารณะของ S4 eMediation — ยื่นคำร้อง (
/public/request,/public/request-ap), สมัครผู้ไกล่เกลี่ย, ยื่นจัดตั้งศูนย์ — captcha บวกเลข/รหัสภาพเดิมถูกถอดออกทั้งหมด. โมดูลอยู่ในไลบรารีกลาง@rlpdxmfec-devcode/rlpdjs@0.8.0— ทุกระบบ S1–S8 นำไปใช้ได้ทันที.
ทำไมต้อง ALTCHA (นอกเหนือ TOR — ไม่มีค่าใช้จ่ายเพิ่ม)¶
| ประเด็น | captcha เดิม (บวกเลข/รหัสภาพ) | ALTCHA proof-of-work |
|---|---|---|
| ความปลอดภัย | bot อ่านโจทย์จาก client ได้ → ผ่านอัตโนมัติ | ต้องเผา CPU แก้โจทย์ crypto ต่อ 1 คำขอ; ตรวจซ้ำฝั่ง server เสมอ |
| Self-hosted | ✅ | ✅ 100% — ไม่มี Cloudflare/Google/hCaptcha, ไม่มี CDN, ไม่มีบัญชีภายนอก |
| PDPA | ✅ | ✅ ไม่มี cookie/fingerprint/tracking |
| การเข้าถึง (WCAG 2.2 AA) | ⚠️ ต้องอ่านเลข/ภาพ | ✅ คลิกเดียว, คีย์บอร์ด/screen reader, ภาษาไทย |
| ใช้ซ้ำ/Replay | กันด้วย jti ในหน่วยความจำ | payload ใช้ครั้งเดียว + หมดอายุ 5 นาที (ผูกลายเซ็น HMAC) |
สถาปัตยกรรม: server ออก challenge (HMAC-signed, มีอายุ) → widget ในเบราว์เซอร์แก้โจทย์ PBKDF2 ใน web worker → ส่ง payload มากับฟอร์ม → server ตรวจ (ลายเซ็น + PoW + หมดอายุ + single-use) ก่อนเขียนฐานข้อมูลเสมอ — สถานะ "verified" ฝั่ง client เป็นแค่ UX.
การนำไปใช้ในระบบอื่น (S1–S8) — 4 ขั้น¶
ไลบรารี: ใช้ vendored tarball เป็นมาตรฐาน (npm pack จาก rlpdjs main → vendor/…tgz →
dependency แบบ file: — ไม่ต้องมี registry token บนเครื่อง build; ดู rlpdjs SKILL.md).
- ลงทะเบียนโมดูล (
app.module.ts):AltchaModule.forRoot({ ...altchaOptionsFromEnv(), hmacKey: <server-only secret> })—ALTCHA_HMAC_KEYสร้างด้วยopenssl rand -base64 48; ระบบ ไม่ boot ใน production ถ้าไม่ตั้ง. - Endpoint แจก challenge — ต้องตอบ JSON ดิบ (ห้ามครอบ envelope):
res.setHeader('Cache-Control','no-store'); res.json(await altcha.createChallenge()); - ป้องกัน endpoint ธุรกิจ — DTO เพิ่ม
@IsString() @IsNotEmpty() @MaxLength(4096) altcha!: string;แล้วใน service:if (!(await altcha.verify(dto.altcha)).ok) throw <400>;ก่อน side effect ทุกครั้ง. - Frontend —
npm i altcha; ใช้<AltchaWidget>ตัวอย่างที่emediation/frontend/src/components/common/altcha.jsx(Thai i18n, mock/test mode, reset หลัง submit เพราะ payload ใช้ครั้งเดียว).
ข้อกำหนดตอน Deploy (สำคัญ)¶
ALTCHA_HMAC_KEYต้องถูกตั้งใน env ของ UAT/production ก่อน deploy build ที่มี ALTCHA (fail-fast by design — ไม่ตั้ง = service ไม่ start). ห้าม commit ค่าใน repo, ห้าม log.TRUST_PROXY_HOPS=1ในทุก deploy ที่อยู่หลัง nginx/reverse proxy — ไม่งั้น rate-limit ต่อ IP จะนับ IP ของ proxy แทน client (ตั้งเป็นจำนวน hop จริง ห้ามตั้งtrue).- ปรับความยาก/อายุได้ผ่าน env:
ALTCHA_COST(5000),ALTCHA_COUNTER_MIN/MAX(5000/10000),ALTCHA_TTL_MS(300000). ระบบหลาย instance: ส่งreplayStore(Redis/DB) แทน in-memory (ความเสี่ยงตกค้างถูกจำกัดด้วย TTL 5 นาทีอยู่แล้ว).
หลักฐานการตรวจสอบ (S4, 12 ส.ค. 2569)¶
- rlpdjs jest 33/33 (รวมเคสโจมตี: payload ถูกแก้, กุญแจผิด, หมดอายุ, ใช้ซ้ำ) ·
S4 backend e2e 36/36 (journey
public-intake-altcha10 จุดตรวจ ครบ 3 endpoint) · Playwright เบราว์เซอร์จริง: แก้ PoW + ยื่นคำร้องสำเร็จ (HTTP 201) + widget reset. - ผ่าน security review (ไม่พบช่องโหว่ exploitable) และ code review อิสระ.
- โค้ด: rlpdjs
src/altcha/(commit3cdaed8, เผยแพร่เป็น 0.8.0) · emediation commits164d4c5+f35e912· แผนงานemediation/plans/altcha-anti-bot.md.
S6 OCIPA — ใช้ ALTCHA ผ่าน "central captcha service" ของ S9 (ต่างจาก S4)¶
สถานะ (30 ส.ค. 2569): ใช้งานจริงบน UAT —
https://uat-ocipa-front.rlpd.go.thแบบฟอร์มประชาชน (/ocipaวิซาร์ดยื่นคำขอ + OTP, ติดตามสถานะ,/rightsnotification/submitสชง.1/03) มี ALTCHA gate ครบ. e2e 4/4 ผ่าน (challenge 200, ไม่ติ๊ก →Ref1=CAPTCHA, payload ที่แก้แล้วผ่าน + replay ถูกปฏิเสธ).
S6 ocipa เป็น .NET Framework 4.7.2 (legacy) รันแยกไม่ใช่บนสแตก Node — จึง รัน rlpdjs verifier เองไม่ได้. แทนที่จะฝัง verifier, ocipa เป็น ผู้บริโภค ของ central captcha service บน S9 web_portal BFF:
- widget เรียก
/captcha/challengeของ ocipa เอง (same-origin) ซึ่ง proxy ต่อไปที่ BFFGET {base}/captcha/altcha/challenge(เลี่ยง CORS) - ฝั่ง server ของ ocipa (
AltchaVerifier) POST payload แบบ server-to-server ไปที่ BFFPOST {base}/captcha/altcha/verifyพร้อม headerx-api-key(คีย์รายระบบ) ก่อน side effect - BFF ยังคงเป็นเจ้าของ HMAC/PoW/single-use เหมือน S4 — ocipa แค่ถามผลว่า
{ok:true|false}
คีย์คอนฟิก (ชื่อ env เท่านั้น — ค่าลับอยู่ที่ credentials/uat_devphase2_sso_secrets.md)¶
| ฝั่ง | ที่ตั้งค่า (แหล่งจริง = GitHub pipeline env uat) |
ชื่อ | ความหมาย |
|---|---|---|---|
| S9 BFF | secret | WEBPORTAL_CAPTCHA_API_KEYS |
คีย์รายระบบ app:key (คั่นด้วย comma) — ที่นี่คือ ocipa:<คีย์> |
| S9 BFF | container rlpd-webportal-be (.155) |
CAPTCHA_API_KEYS |
มาจาก secret ข้างบน (compose deploy/webportal/uat) — ไม่ตั้ง = verify ตอบ 503 |
| S6 ocipa | secret | OCIPA_CAPTCHA_API_KEY |
คีย์เดิม (raw ไม่มี prefix) ที่ ocipa ส่งใน x-api-key |
| S6 ocipa | variable | OCIPA_CAPTCHA_BASE_URL |
base URL ของ BFF รวม /api = https://uat-webportal.rlpd.go.th/api |
| S6 ocipa | เครื่อง .156 | machine env OCIPA_CAPTCHA_API_KEY + secrets.config CaptchaServiceBaseUrl |
render โดย ocipa.yml จาก secret/variable ข้างบน |
OCIPA_CAPTCHA_API_KEY(=<คีย์>) และWEBPORTAL_CAPTCHA_API_KEYS(=ocipa:<คีย์>) ต้องเป็น คีย์เดียวกัน ไม่งั้น verify 401. ทั้งสองด้าน "ครึ่ง ๆ" = gate ปิด (ไม่ fail-closed) — ตั้งครบทั้งคู่เสมอ.
⚠️ กับดัก TLS 1.2 (สาเหตุอาการ "ตั้งค่าครบแล้วแต่ challenge ยัง 502")¶
ocipa (.156) เป็น .NET Framework ที่ตั้ง <httpRuntime targetFramework="4.5.2"> → ดีฟอลต์
ServicePointManager เป็น TLS 1.0; แต่ nginx ของ BFF รับ เฉพาะ TLS 1.2 → การเรียก
server-to-server ทุกครั้ง throw "Could not create SSL/TLS secure channel" แล้ว CaptchaController
ตอบ 502 (gate ใช้ไม่ได้ทั้งที่ค่าถูกครบ). แก้แบบ machine-wide บน .156:
SchUseStrongCrypto=1 + SystemDefaultTlsVersions=1 (DWORD) ใต้
HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 และ WOW6432Node (app pool รันแบบ 32-bit)
แล้ว recycle app pool. ทำให้ถาวรใน pipeline deploy/ocipa/uat/deploy-iis.ps1.
วิธีตรวจ / รันซ้ำ¶
cd RLPD_REPOS/ocipa/e2e && npm install && OCIPA_BASE_URL=https://uat-ocipa-front.rlpd.go.th npx playwright test
(ต้องต่อ VPN). โค้ด/แผน: ocipa CommonProvide/AltchaVerifier.cs · Controllers/CaptchaController.cs ·
Views/Shared/_AltchaWidget.cshtml · แผนงาน ocipa/plans/2026-08-16-altcha-public-form-gate.md ·
BFF webportal/backend/src/{middlewares/CaptchaApiKey.ts,controllers/core/captcha} ·
pipeline deploy/{webportal,ocipa}/uat/.