พร็อกซีข้อมูลรับรอง — ทางเทคนิค
วิธีการทำงานของพร็อกซี
สิ่งที่ระบบป้องกัน และสิ่งที่ระบบไม่ได้ป้องกัน
เพจนี้ออกแบบมาสำหรับผู้ตรวจสอบความปลอดภัย ผู้ทดสอบการเจาะระบบ และวิศวกรที่กำลังประเมินแบบจำลองภัยคุกคามของพร็อกซี โดยอธิบายการทำงานของพร็อกซีในระดับโปรโตคอล ตำแหน่งที่ข้อมูลรับรองอยู่ในหน่วยความจำ และพื้นผิวการโจมตีที่ยังคงเหลืออยู่
สถาปัตยกรรม
พร็อกซีนี้คือ HTTPS MITM พร็อกซีที่ใช้ CONNECT โดย AI เอเจนต์จะตั้งค่า HTTPS_PROXY ให้ชี้ไปที่พร็อกซี เมื่อเอเจนต์ส่งคำขอ HTTPS พร็อกซีจะดักจับการเชื่อมต่อ TLS ตรวจสอบเฮดเดอร์ของคำขอเพื่อหาการอ้างอิงข้อมูลรับรอง ดึงข้อมูลจากห้องนิรภัย Clavitor และส่งต่อคำขอพร้อมข้อมูลรับรองที่แทรกเข้าไปยัง API ปลายทาง
โดยค่าเริ่มต้น พร็อกซีจะลิสเทนที่ 127.0.0.1:1983 ซึ่งเป็นรูปแบบ sidecar ที่พร็อกซีและเอเจนต์ใช้โฮสต์ร่วมกัน สำหรับการปรับใช้แบบแชร์ (พร็อกซีหนึ่งตัวให้บริการเอเจนต์หลายตัวบนเครือข่ายส่วนตัว, container sidecar สำหรับหลายเวิร์กโหลด, โฮสต์พร็อกซีเฉพาะ) สามารถกำหนดค่าอินเทอร์เฟซการลิสเทนได้ผ่าน CLAVITOR_PROXY_LISTEN
พร็อกซีเป็น Go binary แบบสแตนด์อโลน ไม่ใช้ CGO การเข้ารหัสลับของโปรโตคอล Clavitor ทั้งหมดจะทำงานผ่านการใช้งาน Rust แบบมาตรฐานที่คอมไพล์เป็น WebAssembly และโหลดผ่าน wazero เมื่อเริ่มทำงาน
การจัดการ TLS
พร็อกซีจะสร้าง root CA แบบ ECDSA P-256 ที่ลงนามด้วยตนเองในการรันครั้งแรก และบันทึกไว้ในไดเรกทอรีของ binary ในโหมด 0600 สำหรับแต่ละโฮสต์ upstream จะมีการสร้าง leaf certificate ตามความต้องการ ลงนามโดย CA นี้ และแคชไว้ในหน่วยความจำพร้อมการลบแบบมีขอบเขต (1,000 โฮสต์) leaf certificate มีอายุ 24 ชั่วโมงและจะถูกสร้างใหม่อย่างโปร่งใสที่ชั่วโมงที่ 23 เพื่อป้องกันไม่ให้หมดอายุระหว่างเซสชัน
เอเจนต์ต้องเชื่อถือใบรับรอง CA ของพร็อกซี ส่งออกด้วยคำสั่ง clavitor-proxy ca
การเชื่อมต่อ upstream ใช้ TLS 1.3 เป็นขั้นต่ำพร้อมการเจรจา ALPN สำหรับ HTTP/2 และ HTTP/1.1 ใช้ system certificate pool สำหรับการตรวจสอบ upstream ไม่มีการปักหมุดใบรับรอง (certificate pinning) — พร็อกซีจะเชื่อถือสิ่งที่ OS เชื่อถือ
ข้อมูลรับรองจะไม่ถูกแคช ไม่ถูกเขียนลงดิสก์ และไม่ถูกเก็บไว้นานกว่าหนึ่งคำขอ HTTP
| ระยะ | ตำแหน่งที่ข้อมูลรับรองอยู่ | ระยะเวลา |
|---|---|---|
| ขณะพักในห้องนิรภัย | ข้อความเข้ารหัส AES-GCM ในฐานข้อมูลห้องนิรภัย | จนกว่าจะถูกลบ |
| ขณะส่งไปยังพร็อกซี | การตอบสนอง JSON ที่เข้ารหัส TLS จาก API ของห้องนิรภัย | หนึ่งรอบการเดินทางของ HTTP |
| ถอดรหัสในพร็อกซี | หน่วยความจำกระบวนการ (Go string บน heap) | หนึ่งคำขอ HTTP |
| แทรกเข้าไปในคำขอ upstream | ไบต์ที่เข้ารหัส TLS บนสายส่งไปยัง upstream | หนึ่งคำขอ HTTP |
พร็อกซีเก็บคีย์ถอดรหัสข้อมูลรับรองของเอเจนต์ (16 ไบต์) ไว้ในหน่วยความจำตลอดระยะเวลาการทำงาน คีย์นี้จะถูกโหลดจากการตั้งค่า sidecar ที่เข้ารหัส (รูปแบบ CLV1) เมื่อเริ่มทำงาน และจะถูกล้างออกเมื่อปิดการทำงานอย่างสมบูรณ์ คีย์นี้จะไม่ออกจากกระบวนการเด็ดขาด
การตั้งค่า sidecar ถูกเข้ารหัสด้วย AES-128-GCM และ HMAC-SHA256 โดยใช้คีย์แบบ deterministic ที่ได้จาก seed แบบคงที่ นี่คือการปิดบัง ไม่ใช่การรักษาความลับ — ขอบเขตความปลอดภัยคือสิทธิ์ของไฟล์ (0600) และการครอบครองไฟล์ รูปแบบ CLV1 ถูกใช้ร่วมกันระหว่างพร็อกซี CLI และส่วนขยายเบราว์เซอร์
โหมดการดึงข้อมูล
โหมด 1 — placeholder แบบชัดเจน
เอเจนต์รวมการอ้างอิง clavitor://Entry/field ในเฮดเดอร์ของคำขอ พร็อกซีจะค้นหาเอนทรีในห้องนิรภัยตามชื่อ ดึงข้อมูล ถอดรหัสฟิลด์ที่ระบุ และแทนที่ placeholder ด้วยค่าจริง
หากการค้นหาไม่ส่งคืนผลลัพธ์หรือส่งคืนมากกว่าหนึ่งผลลัพธ์ พร็อกซีจะส่งคืน 502 พร้อมรหัสข้อผิดพลาดที่เสถียร placeholder จะไม่ถูกเอาออกและส่งต่อตามเดิมเด็ดขาด
โหมด 2 — การจับคู่ URL
เมื่อไม่มี placeholder พร็อกซีจะขอให้ห้องนิรภัยส่งเอนทรีที่ฟิลด์ URL ตรงกับโฮสต์ upstream หากมีการจับคู่เพียงรายการเดียวที่มีรูปแบบฟิลด์ที่รู้จัก พร็อกซีจะแทรกข้อมูลรับรองโดยอัตโนมัติ
ไม่มีการจับคู่ → ส่งผ่าน (ไม่คาดหวังข้อมูลรับรอง) การจับคู่หลายรายการ → 502 พร้อมคำแนะนำการแยกความแตกต่าง รูปแบบฟิลด์ที่ไม่รู้จัก → 502
ต้นไม้การตัดสินใจเป็นแบบ deterministic: มี placeholder → ดึงข้อมูลหรือล้มเหลว ไม่มี placeholder → จับคู่ URL หรือส่งผ่าน ไม่มีเส้นทาง fallback แบบเงียบที่การดึงข้อมูลล้มเหลวแล้วส่งผลให้คำขอไปยัง upstream โดยไม่มีข้อมูลรับรอง
โดยค่าเริ่มต้น ห้องนิรภัยจะเห็น agent ID ของพร็อกซีเองในทุกคำขอ ขีดจำกัดอัตรา การตรวจสอบขอบเขต และรายการบันทึกการตรวจสอบจะถูกระบุว่าเป็นของพร็อกซี
เมื่อเอเจนต์หลายตัวใช้พร็อกซีอินสแตนซ์เดียวกัน placeholder สามารถรวม agent ID ได้: clavitor://agentid@Entry/field พร็อกซีจะส่ง agent ID นี้ไปยังห้องนิรภัย ซึ่งจะนำขอบเขตและขีดจำกัดอัตราของเอเจนต์นั้นมาใช้ และบันทึกการเข้าถึงสำหรับเอเจนต์นั้น agent ID คือค่าฐานสิบหก 32 อักขระที่แสดงในหน้ารายละเอียดเอเจนต์ใน UI ของห้องนิรภัย
# Without agent ID — attributed to the proxy Authorization: Bearer clavitor://OpenAI/key # With agent ID — attributed to agent 0102030405060708090a0b0c0d0e0f10 Authorization: Bearer clavitor://0102030405060708090a0b0c0d0e0f10@OpenAI/key
| การปรับใช้ | แบบจำลองข้อมูลระบุตัวตน | การแยก |
|---|---|---|
| หนึ่งพร็อกซีต่อหนึ่งเอเจนต์ | Proxy ID = agent ID (ค่าเริ่มต้น) | เต็มรูปแบบ — binary, การตั้งค่า, ขอบเขต, ขีดจำกัดอัตราแยกต่างหาก |
| พร็อกซีแบบแชร์ ไม่มี agent ID ใน URL | เอเจนต์ทั้งหมดใช้ ID ของพร็อกซีร่วมกัน | ขอบเขตและขีดจำกัดอัตราแบบแชร์ |
พร็อกซีแบบแชร์ + agentid@ ใน URL | ข้อมูลระบุตัวตนต่อเอเจนต์ | ขอบเขต ขีดจำกัดอัตรา และการตรวจสอบต่อเอเจนต์ |
agent ID ใน URL ไม่ใช่กลไกการพิสูจน์ตัวตน — โทเค็น CVT ของพร็อกซีจะเป็นผู้พิสูจน์ตัวตนการเชื่อมต่อ agent ID จะกำหนดการระบุแหล่งที่มา: ขอบเขตของใครที่ถูกนำมาใช้ ขีดจำกัดอัตราของใครที่ถูกนับ และเส้นทางการตรวจสอบของใครที่บันทึกการเข้าถึง ห้องนิรภัยจะปฏิเสธ agent ID ที่ไม่รู้จักด้วยความล้มเหลวที่ชัดเจน
ความปลอดภัยของเครือข่าย
การป้องกัน SSRF
โดยค่าเริ่มต้น พร็อกซีจะบล็อกการเชื่อมต่อ upstream ไปยังเครือข่ายส่วนตัว (RFC 1918), metadata ของอินสแตนซ์คลาวด์ (169.254.169.254), loopback, link-local และช่วง carrier-grade NAT DNS จะถูกแก้ปัญหาก่อน IP ที่ส่งคืนทั้งหมดจะได้รับการตรวจสอบก่อนทำการเชื่อมต่อ TCP ซึ่งเป็นการปิดช่องโหว่ DNS rebinding TOCTOU
แทนที่ด้วย CLAVITOR_PROXY_ALLOW_PRIVATE=true สำหรับเอเจนต์ที่ต้องเข้าถึง API ส่วนตัวอย่างถูกต้อง
การปักหมุดเป้าหมาย
โฮสต์เป้าหมาย CONNECT จะถูกจับเมื่อมีการสร้างอุโมงค์และใช้ตลอดอายุของอุโมงค์ คำขอถัดไปภายในอุโมงค์ไม่สามารถเปลี่ยนเส้นทางไปยังโฮสต์อื่นโดยการจัดการเฮดเดอร์ Host ได้ ความไม่ตรงกันจะส่งผลให้ได้ 502
สิ่งนี้ป้องกันไม่ให้เอเจนต์สร้างอุโมงค์ไปยัง api.openai.com แล้วส่งคำขอไปยัง internal-service.corp
การจัดการเฮดเดอร์
เฮดเดอร์แบบ hop-by-hop จะถูกเอาออกจากทั้งคำขอและการตอบสนองตาม RFC 7230 §6.1: Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection, TE, Trailers, Transfer-Encoding, Upgrade
Set-Cookie จะถูกเอาออกจากการตอบสนองของ upstream เพื่อป้องกันไม่ให้ upstream ฝังคุกกี้ในไคลเอนต์ HTTP ของเอเจนต์
เนื้อหาคำขอและการตอบสนองจะสตรีมผ่านโดยไม่มีการบัฟเฟอร์ เนื้อหาคำขอถูกจำกัดที่ 64 MB โดยค่าเริ่มต้น (CLAVITOR_PROXY_MAX_BODY_MB) เนื้อหาการตอบสนองจะสตรีมโดยไม่มีขีดจำกัดตายตัว จะมีการแจ้งเตือนในบันทึกเมื่อ Content-Length เกิน 100 MB
ในโหมดจับคู่ URL พร็อกซีจะแมปป้ายกำกับฟิลด์ของห้องนิรภัยกับเฮดเดอร์ HTTP:
| ป้ายกำกับฟิลด์ | เฮดเดอร์ที่แทรก |
|---|---|
key, apikey, api_key, token, secret, bearer, access_token | Authorization: Bearer <value> |
x-api-key, api-key | X-API-Key: <value> |
username + password (จับคู่) | Authorization: Basic base64(user:pass) |
| อื่นๆ | ถูกปฏิเสธ — ERR-PROXY-052 |
ในโหมด placeholder เอเจนต์จะควบคุมว่าฟิลด์ใดถูกดึงข้อมูลและไปที่ไหน การแมปด้านบนใช้กับโหมดจับคู่ URL เท่านั้น
ความล้มเหลวทุกครั้งจะสร้างรหัส ERR-PROXY-NNN ที่เสถียร รหัสเหล่านี้เป็นส่วนหนึ่งของอินเทอร์เฟซสาธารณะของพร็อกซี — เอเจนต์และผู้ปฏิบัติงานสามารถจับคู่รหัสเหล่านี้เพื่อการแจ้งเตือนและการดีบัก
| ช่วง | หมวดหมู่ |
|---|---|
001–019 | การตั้งค่า (config, init, การสร้าง CA, WASM) |
020–029 | วงจรชีวิตของ Daemon |
030–049 | การดึงข้อมูล placeholder (URI clavitor://) |
050–069 | การแทรกแบบจับคู่ URL |
070–089 | Upstream / TLS |
ไม่สามารถเข้าถึงฟิลด์ข้อมูลระบุตัวตนได้
เอนทรีในห้องนิรภัยรองรับการเข้ารหัสสามระดับ ฟิลด์ที่มีการเข้ารหัสห้องนิรภัยคือ metadata แบบข้อความธรรมดา ฟิลด์ที่มีการเข้ารหัสข้อมูลรับรองจะถูกถอดรหัสด้วยคีย์ของเอเจนต์ ฟิลด์ที่มีการเข้ารหัสข้อมูลระบุตัวตนจะถูกเข้ารหัสด้วยคีย์ที่เซิร์ฟเวอร์และพร็อกซีไม่เคยเห็น มีเพียงเจ้าของห้องนิรภัยเท่านั้นที่สามารถถอดรหัสได้ผ่านฮาร์ดแวร์คีย์เพื่อความปลอดภัยของตน
หาก placeholder อ้างอิงถึงฟิลด์ที่มีการเข้ารหัสข้อมูลระบุตัวตน พร็อกซีจะส่งคืน ERR-PROXY-035 ไม่มี fallback ไม่มีผลลัพธ์บางส่วน ฟิลด์นี้ไม่สามารถเข้าถึงได้จากพร็อกซีในทางสถาปัตยกรรม
สิ่งที่พร็อกซีไม่ได้ป้องกัน
แบบจำลองภัยคุกคามของพร็อกซีคือ skill ที่ถูกโจมตีหรือการแทรก prompt ที่ทำให้เอเจนต์ที่พิสูจน์ตัวตนแล้วรวบรวมข้อมูลรับรอง ขีดจำกัดอัตราต่อเอเจนต์ โควตาเอนทรีที่ไม่ซ้ำกัน และการล็อกดาวน์แบบสองครั้งของห้องนิรภัยคือการป้องกันหลัก พร็อกซีเพิ่มจุดบังคับใช้ในระดับเครือข่ายซึ่งข้อมูลรับรองจะถูกดึงตามคำขอและไม่ถูกเก็บไว้โดยเอเจนต์
พร็อกซีทำงานบนเครื่องเดียวกับเอเจนต์ ผู้โจมตีที่มีสิทธิ์ root สามารถอ่านหน่วยความจำของกระบวนการ แนบ debugger หรือดักจับการจราจร loopback ได้ พร็อกซีเป็นเลเยอร์การแทรกข้อมูลรับรอง ไม่ใช่ขอบเขตความปลอดภัยของฮาร์ดแวร์
หาก API upstream ส่งข้อมูลรับรองกลับในการตอบสนอง (เช่น endpoint "whoami") เอเจนต์จะเห็นข้อมูลนั้น พร็อกซีแทรกข้อมูลรับรองในคำขอ ไม่ใช่การตอบสนอง และไม่ได้กรองสิ่งที่ส่งกลับมา
การบันทึก
พร็อกซีบันทึกหนึ่งบรรทัดต่อ CONNECT ที่ยอมรับ และแสดงบรรทัดข้อผิดพลาดสำหรับความล้มเหลว พร็อกซีจะไม่บันทึกสิ่งต่อไปนี้เด็ดขาด:
- ค่าข้อมูลรับรองที่ถอดรหัสแล้ว
- URL คำขอแบบเต็ม (query string อาจมีข้อมูลลับ — บันทึกเฉพาะ scheme + host + path)
- เนื้อหาคำขอหรือการตอบสนอง
- คีย์ถอดรหัสข้อมูลรับรองหรือเนื้อหาการตั้งค่า sidecar
เมื่อพร็อกซีตรวจพบว่าการตอบสนอง 400 จาก upstream มีคีย์เวิร์ดที่เกี่ยวข้องกับการพิสูจน์ตัวตน (unauthorized, invalid token ฯลฯ) พร็อกซีจะบันทึกคำแนะนำการวินิจฉัยว่าข้อมูลรับรองที่แทรกอาจล้าสมัย การตอบสนองจะถูกส่งต่อโดยไม่มีการเปลี่ยนแปลง
การเข้ารหัสลับ
การเข้ารหัสลับของโปรโตคอล Clavitor ทั้งหมด — การถอดรหัสฟิลด์ AES-GCM, การได้มาของคีย์ HKDF, การเข้ารหัส base62, การสร้างโทเค็น CVT, การ pack/unpack การตั้งค่า CLV1 — ทำงานภายในโมดูล WebAssembly เดียว (clavis_crypto.wasm) ที่โหลดผ่าน wazero ซึ่งเป็น WASM runtime แบบ pure-Go ไม่ใช้ CGO ไม่มีการเขียน Clavitor primitives ใหม่ใน Go
โมดูล WASM ถูกคอมไพล์จาก Rust crate เดียวกัน (clavis-crypto) ที่ใช้โดยเบราว์เซอร์ CLI และส่วนขยายเบราว์เซอร์ แหล่งความจริงเดียว binary เดียว พื้นผิวการตรวจสอบเดียว
พร็อกซีใช้ crypto/tls ของ Go สำหรับ TLS wire และ crypto/ecdsa สำหรับการสร้างใบรับรอง MITM สิ่งเหล่านี้เป็นเรื่องของการขนส่ง ไม่ใช่การดำเนินงานของโปรโตคอล Clavitor
ข้อมูลลับ (คีย์ถอดรหัสข้อมูลรับรอง, agent ID, device ID, URL ห้องนิรภัย) จะอยู่ในการตั้งค่า sidecar CLV1 ที่เข้ารหัส ซึ่งเขียนครั้งเดียวระหว่าง clavitor-proxy init ตัวควบคุมการทำงานจะอยู่ในตัวแปรสภาพแวดล้อม:
| ตัวแปร | ค่าเริ่มต้น | วัตถุประสงค์ |
|---|---|---|
CLAVITOR_PROXY_LISTEN | 127.0.0.1 | อินเทอร์เฟซการลิสเทน ตั้งค่าเป็น 0.0.0.0 สำหรับการปรับใช้แบบแชร์ หรือเป็น IP ของอินเทอร์เฟซเฉพาะ |
CLAVITOR_PROXY_PORT | 1983 | พอร์ตการลิสเทน |
CLAVITOR_PROXY_ALLOW_PRIVATE | false | อนุญาตการเชื่อมต่อไปยังเครือข่าย RFC-1918 / ส่วนตัว |
CLAVITOR_PROXY_MAX_BODY_MB | 64 | ขีดจำกัดขนาดเนื้อหาคำขอ |
CLAVITOR_PROXY_WRITE_TIMEOUT | 300 | หมดเวลาเขียนการตอบสนองเป็นวินาที |
CLAVITOR_CONFIG | (ไดเรกทอรี exe) | แทนที่เส้นทางการตั้งค่า sidecar |
ตัวควบคุมการทำงานไม่ใช่ข้อมูลลับ ไม่ควรอยู่ในการตั้งค่าที่เข้ารหัส ควรอยู่ในที่ที่เครื่องมือการปรับใช้จัดการอยู่แล้ว — สภาพแวดล้อม
คุณสามารถตรวจสอบสิ่งนี้ได้ด้วยตนเองครับ
การเข้ารหัสลับเป็น artifact WASM เดียวที่สามารถตรวจสอบได้ แบบจำลองภัยคุกคามได้รับการจัดทำเอกสารไว้ หากคุณพบสิ่งที่เราพลาดไป เราต้องการรับทราบครับ