พร็อกซีข้อมูลรับรอง — ทางเทคนิค

วิธีการทำงานของพร็อกซี

สิ่งที่ระบบป้องกัน และสิ่งที่ระบบไม่ได้ป้องกัน

เพจนี้ออกแบบมาสำหรับผู้ตรวจสอบความปลอดภัย ผู้ทดสอบการเจาะระบบ และวิศวกรที่กำลังประเมินแบบจำลองภัยคุกคามของพร็อกซี โดยอธิบายการทำงานของพร็อกซีในระดับโปรโตคอล ตำแหน่งที่ข้อมูลรับรองอยู่ในหน่วยความจำ และพื้นผิวการโจมตีที่ยังคงเหลืออยู่

สถาปัตยกรรม

พร็อกซีนี้คือ HTTPS MITM พร็อกซีที่ใช้ CONNECT โดย AI เอเจนต์จะตั้งค่า HTTPS_PROXY ให้ชี้ไปที่พร็อกซี เมื่อเอเจนต์ส่งคำขอ HTTPS พร็อกซีจะดักจับการเชื่อมต่อ TLS ตรวจสอบเฮดเดอร์ของคำขอเพื่อหาการอ้างอิงข้อมูลรับรอง ดึงข้อมูลจากห้องนิรภัย Clavitor และส่งต่อคำขอพร้อมข้อมูลรับรองที่แทรกเข้าไปยัง API ปลายทาง

โดยค่าเริ่มต้น พร็อกซีจะลิสเทนที่ 127.0.0.1:1983 ซึ่งเป็นรูปแบบ sidecar ที่พร็อกซีและเอเจนต์ใช้โฮสต์ร่วมกัน สำหรับการปรับใช้แบบแชร์ (พร็อกซีหนึ่งตัวให้บริการเอเจนต์หลายตัวบนเครือข่ายส่วนตัว, container sidecar สำหรับหลายเวิร์กโหลด, โฮสต์พร็อกซีเฉพาะ) สามารถกำหนดค่าอินเทอร์เฟซการลิสเทนได้ผ่าน CLAVITOR_PROXY_LISTEN

illustration: unknown name=proxy-sequence

พร็อกซีเป็น 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 เชื่อถือ

Credential lifecycle

ข้อมูลรับรองจะไม่ถูกแคช ไม่ถูกเขียนลงดิสก์ และไม่ถูกเก็บไว้นานกว่าหนึ่งคำขอ 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 identity

โดยค่าเริ่มต้น ห้องนิรภัยจะเห็น 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

Field-to-header mapping

ในโหมดจับคู่ URL พร็อกซีจะแมปป้ายกำกับฟิลด์ของห้องนิรภัยกับเฮดเดอร์ HTTP:

ป้ายกำกับฟิลด์เฮดเดอร์ที่แทรก
key, apikey, api_key, token, secret, bearer, access_tokenAuthorization: Bearer <value>
x-api-key, api-keyX-API-Key: <value>
username + password (จับคู่)Authorization: Basic base64(user:pass)
อื่นๆถูกปฏิเสธ — ERR-PROXY-052

ในโหมด placeholder เอเจนต์จะควบคุมว่าฟิลด์ใดถูกดึงข้อมูลและไปที่ไหน การแมปด้านบนใช้กับโหมดจับคู่ URL เท่านั้น

Error codes

ความล้มเหลวทุกครั้งจะสร้างรหัส ERR-PROXY-NNN ที่เสถียร รหัสเหล่านี้เป็นส่วนหนึ่งของอินเทอร์เฟซสาธารณะของพร็อกซี — เอเจนต์และผู้ปฏิบัติงานสามารถจับคู่รหัสเหล่านี้เพื่อการแจ้งเตือนและการดีบัก

ช่วงหมวดหมู่
001–019การตั้งค่า (config, init, การสร้าง CA, WASM)
020–029วงจรชีวิตของ Daemon
030–049การดึงข้อมูล placeholder (URI clavitor://)
050–069การแทรกแบบจับคู่ URL
070–089Upstream / TLS

ไม่สามารถเข้าถึงฟิลด์ข้อมูลระบุตัวตนได้

เอนทรีในห้องนิรภัยรองรับการเข้ารหัสสามระดับ ฟิลด์ที่มีการเข้ารหัสห้องนิรภัยคือ metadata แบบข้อความธรรมดา ฟิลด์ที่มีการเข้ารหัสข้อมูลรับรองจะถูกถอดรหัสด้วยคีย์ของเอเจนต์ ฟิลด์ที่มีการเข้ารหัสข้อมูลระบุตัวตนจะถูกเข้ารหัสด้วยคีย์ที่เซิร์ฟเวอร์และพร็อกซีไม่เคยเห็น มีเพียงเจ้าของห้องนิรภัยเท่านั้นที่สามารถถอดรหัสได้ผ่านฮาร์ดแวร์คีย์เพื่อความปลอดภัยของตน

หาก placeholder อ้างอิงถึงฟิลด์ที่มีการเข้ารหัสข้อมูลระบุตัวตน พร็อกซีจะส่งคืน ERR-PROXY-035 ไม่มี fallback ไม่มีผลลัพธ์บางส่วน ฟิลด์นี้ไม่สามารถเข้าถึงได้จากพร็อกซีในทางสถาปัตยกรรม

สิ่งที่พร็อกซีไม่ได้ป้องกัน

แบบจำลองภัยคุกคามของพร็อกซีคือ skill ที่ถูกโจมตีหรือการแทรก prompt ที่ทำให้เอเจนต์ที่พิสูจน์ตัวตนแล้วรวบรวมข้อมูลรับรอง ขีดจำกัดอัตราต่อเอเจนต์ โควตาเอนทรีที่ไม่ซ้ำกัน และการล็อกดาวน์แบบสองครั้งของห้องนิรภัยคือการป้องกันหลัก พร็อกซีเพิ่มจุดบังคับใช้ในระดับเครือข่ายซึ่งข้อมูลรับรองจะถูกดึงตามคำขอและไม่ถูกเก็บไว้โดยเอเจนต์

โฮสต์ที่ถูกโจมตี

พร็อกซีทำงานบนเครื่องเดียวกับเอเจนต์ ผู้โจมตีที่มีสิทธิ์ root สามารถอ่านหน่วยความจำของกระบวนการ แนบ debugger หรือดักจับการจราจร loopback ได้ พร็อกซีเป็นเลเยอร์การแทรกข้อมูลรับรอง ไม่ใช่ขอบเขตความปลอดภัยของฮาร์ดแวร์

การลักลอบนำข้อมูลรับรองออกผ่านการตอบสนองของ API

หาก 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

Configuration

ข้อมูลลับ (คีย์ถอดรหัสข้อมูลรับรอง, agent ID, device ID, URL ห้องนิรภัย) จะอยู่ในการตั้งค่า sidecar CLV1 ที่เข้ารหัส ซึ่งเขียนครั้งเดียวระหว่าง clavitor-proxy init ตัวควบคุมการทำงานจะอยู่ในตัวแปรสภาพแวดล้อม:

ตัวแปรค่าเริ่มต้นวัตถุประสงค์
CLAVITOR_PROXY_LISTEN127.0.0.1อินเทอร์เฟซการลิสเทน ตั้งค่าเป็น 0.0.0.0 สำหรับการปรับใช้แบบแชร์ หรือเป็น IP ของอินเทอร์เฟซเฉพาะ
CLAVITOR_PROXY_PORT1983พอร์ตการลิสเทน
CLAVITOR_PROXY_ALLOW_PRIVATEfalseอนุญาตการเชื่อมต่อไปยังเครือข่าย RFC-1918 / ส่วนตัว
CLAVITOR_PROXY_MAX_BODY_MB64ขีดจำกัดขนาดเนื้อหาคำขอ
CLAVITOR_PROXY_WRITE_TIMEOUT300หมดเวลาเขียนการตอบสนองเป็นวินาที
CLAVITOR_CONFIG(ไดเรกทอรี exe)แทนที่เส้นทางการตั้งค่า sidecar

ตัวควบคุมการทำงานไม่ใช่ข้อมูลลับ ไม่ควรอยู่ในการตั้งค่าที่เข้ารหัส ควรอยู่ในที่ที่เครื่องมือการปรับใช้จัดการอยู่แล้ว — สภาพแวดล้อม

คุณสามารถตรวจสอบสิ่งนี้ได้ด้วยตนเองครับ

การเข้ารหัสลับเป็น artifact WASM เดียวที่สามารถตรวจสอบได้ แบบจำลองภัยคุกคามได้รับการจัดทำเอกสารไว้ หากคุณพบสิ่งที่เราพลาดไป เราต้องการรับทราบครับ