บทเรียนจาก Google Maps API Key: เมื่อ “Public API Key” กลายเป็นช่องโหว่
By Chatuphon Chalitthikun,
Penetration Tester Team, Datafarm Company Limited
ผมอยากให้ลองนึกภาพตามนะครับ
คุณเป็น developer คนหนึ่ง วันนึงกำลังทำเว็บแล้วอยากใส่ Google Maps ลงไปในหน้าเว็บ ก็เลยไปเปิด Documentation ของ Google Maps แล้วทำตาม step แบบเป๊ะ ๆ
สร้าง API key เสร็จ ก็เอามาใส่ใน <script> บนหน้าเว็บแบบตรงไปตรงมา
ทุกอย่างทำงานได้ปกติ แผนที่ขึ้น ไม่มี error ไม่มีอะไรแปลก ๆ ให้ต้องกังวล และที่สำคัญ Google เองก็เคยบอกชัดเจนว่า API key แบบนี้ “ไม่ใช่ความลับ” มันถูกออกแบบมาให้ใช้ใน client-side ได้อยู่แล้ว คุณเลยไม่เคยคิดจะซ่อนมันด้วยซ้ำ จากนั้นคุณก็ deploy ขึ้น production แล้วก็ใช้ชีวิตต่อไป ทุกอย่างดูปกติดี ไม่มีอะไรน่าคิดมาก
เวลาผ่านไปเรื่อย ๆ จนคุณแทบจะลืมไปแล้วด้วยซ้ำว่าเคยมี API key ตัวนี้ฝังอยู่ในเว็บ
จนกระทั่งวันหนึ่ง มีเพื่อนร่วมทีมคนนึงเข้าไปใน Google Cloud Platform แล้วกด Enable Generative Language API ขึ้นมา เพราะอยากลองเล่น Gemini ดูเฉย ๆ ซึ่งไม่มี warning ไม่มีอีเมล ไม่มีอะไรเตือนเลยว่าการเปลี่ยนแปลงนี้จะไปกระทบอะไรกับของเดิม
จากนั้นในชั่วข้ามคืน API key ตัวเดิมที่คุณเคยฝังไว้ใน Client ที่ใครก็สามารถเห็นได้ ก็ไม่ได้เป็นแค่ “public key สำหรับ Maps” อีกต่อไป แต่มันกลายเป็น credential ที่สามารถเอาไปเรียก Gemini API ได้ทันที
ซึ่งผลกระทบมันเลยไม่ได้เล็ก ๆ อีกแล้ว เพราะมันไม่ใช่แค่เรื่องแผนที่ แต่กลายเป็นเรื่องค่าใช้จ่าย การใช้ resource และในบางกรณีอาจไปถึงการเข้าถึงข้อมูลบางอย่างใน project ด้วย
แต่ถ้ามองดี ๆ developer ก็ไม่ได้ทำอะไรผิด เราแค่ทำตามที่ platform บอกทุกอย่าง แต่ behavior ของ platform กลับเปลี่ยนทีหลัง ทำให้ assumption เดิมที่ว่า “API key นี้เปิดเผยได้” ไม่จริงอีกต่อไป
มันเกิดขึ้นได้ยังไง?
ก่อนอื่นต้องเข้าใจก่อนว่า Google ใช้ API key format เดียวกัน (AIza...) สำหรับทุก service ทั้ง Maps, Firebase, YouTube และ Gemini ไม่มีการแยกประเภท
ที่ผ่านมาไม่มีปัญหาเพราะ Maps key ถูกออกแบบมาให้เป็น “public identifier” แค่ระบุว่าคำขอนี้มาจาก project ไหนเพื่อเรียกเก็บเงิน ไม่ต่างอะไรจากชื่อบริษัทที่พิมพ์บนใบเสร็จ ปลอดภัยที่จะแสดงต่อสาธารณะ
แต่ Gemini key ต้องการ “sensitive credential” เพราะมันเข้าถึงข้อมูลส่วนตัว ไฟล์ที่ upload ขึ้นไป และ cached content ต้องปกปิดเหมือน password
Google ใช้ format เดียวกันสำหรับทั้งสองอย่าง และเมื่อ enable Gemini ใน project ก็ไม่มีการบอกว่า key เก่าที่มีอยู่แล้วได้รับสิทธิ์ใหม่ไปด้วย
นักวิจัยจาก Truffle Security เรียกสิ่งนี้ว่า Retroactive Privilege Expansion — key ไม่ได้เปลี่ยน โค้ดไม่ได้เปลี่ยน แต่ permission มันเปลี่ยนไปเองโดยที่คุณไม่รู้
ลองเปรียบกับ Stripe ที่เป็นแพลตฟอร์มรับชำระเงินออนไลน์ดูครับจะเห็นภาพชัดขึ้น โดย Stripe จะแยก key ออกเป็นสองแบบตั้งแต่แรก คือ publishable key (ที่ใช้ใน client-side ได้) กับ secret key (ที่ต้องอยู่ใน backend เท่านั้น) อย่างชัดเจนตั้งแต่แรก Google ไม่ได้ทำแบบนั้น และนั่นคือต้นตอของปัญหาทั้งหมด
การสแกน API key จาก Common Crawl
มี dataset สาธารณะตัวหนึ่งชื่อว่า Common Crawl ซึ่งเป็น archive ของหน้าเว็บจากทั่วโลก ขนาดระดับหลายร้อย terabyte ที่ใครก็สามารถดาวน์โหลดไปวิเคราะห์ได้
ลองคิดภาพง่าย ๆ ว่า มันคือ snapshot ของ HTML จากอินเทอร์เน็ตทั้งโลกในช่วงเวลาหนึ่ง และแน่นอนว่า ถ้า API key ของคุณถูกฝังอยู่ใน frontend แบบที่ Google แนะนำ มันก็มีโอกาสสูงมากที่จะถูกเก็บอยู่ใน dataset นี้ด้วย
สิ่งที่ทีมจาก Truffle Security ทำในช่วงเดือนพฤศจิกายน 2025 ก็คือเอา dataset นี้มาสแกนหา pattern ของ Google API key (AIza...) แล้วลองทดสอบว่า key เหล่านั้นยังใช้งานได้อยู่หรือไม่

Source: https://trufflesecurity.com/blog/google-api-keys-werent-secrets-but-then-gemini-changed-the-rules
ผลลัพธ์ออกมาค่อนข้างแรงกว่าที่หลายคนคิด
พวกเขาพบ API key ที่ยังใช้งานได้จริง และสามารถเข้าถึง Gemini API ได้ถึง 2,863 key
และที่น่าสนใจกว่านั้นคือแหล่งที่มาของ key เหล่านี้ไม่ได้มาจากเว็บเล็ก ๆ หรือ project ทดลองเท่านั้น แต่รวมถึง:
- สถาบันการเงิน
- บริษัทด้าน security
- บริษัท recruiting ระดับโลก
และที่น่าตกใจกว่านั้นคือ มี API key ของ Google เอง ที่ถูก deploy อยู่ใน source code ของเว็บไซต์ผลิตภัณฑ์ตั้งแต่ปี 2023 โดยที่ไม่มีใครสังเกตเห็น
ตรงนี้มันสะท้อนอะไรบางอย่างชัดเจนมาก เพราะถ้าแม้แต่ทีมวิศวกรของ Google เองยังสามารถพลาดในรูปแบบนี้ได้ การที่ developer ทั่วไปจะทำตาม documentation แล้วเจอสถานการณ์เดียวกัน ก็คงไม่ใช่เรื่องแปลกอะไรหรือพูดอีกแบบคือ ปัญหานี้มันไม่ได้เกิดจาก “developer careless” แต่เป็นผลจาก design ของระบบที่เปิดโอกาสให้ความผิดพลาดแบบนี้เกิดขึ้นได้ตั้งแต่แรก
ถ้าโดน เสียหายแค่ไหน?
เดือนกุมภาพันธ์ 2026 มีคนโพสต์ในชุมชนออนไลน์ว่าตื่นมาเจอบิล $82,314 ใน 24 ชั่วโมง ทั้งที่ปกติจ่ายแค่เดือนละ $180 นั่นคือค่าใช้จ่ายเพิ่มขึ้นเกือบ 500 เท่าในคืนเดียว

นอกจากนั้น attacker ยังสามารถ list ไฟล์ที่คุณ upload ขึ้น Gemini ได้, อ่าน cached content ได้ และ exhaust quota จนบริการ Gemini ของคุณพังได้ด้วย
ที่น่าหวาดเสียวที่สุดคือวิธีโจมตีแทบไม่ต้องใช้ทักษะอะไรเลย แค่เปิดเว็บ กด Ctrl+U ค้นหา AIza แล้วรัน:
curl “https://generativelanguage.googleapis.com/v1beta/models?key=API\_Here”
ถ้าได้ 200 OK กลับมาพร้อมรายการ models แปลว่า key นั้น vulnerable
Google แก้ไขแล้วหรือยัง?
ในเดือนเมษายน 2026 ผมไปลองดูหน้า Edit API key ใน GCP Console แล้วเจอสิ่งที่ไม่มีในรายงานของ Truffle Security เพราะมันเพิ่งเกิดขึ้น คือ ถ้าคุณเลือกใช้ Generative Language API (Gemini) ระบบจะไม่อนุญาตให้คุณเลือก API อื่นร่วมด้วย

และในทางกลับกัน ถ้าคุณเลือก API ตัวอื่น เช่น Maps JavaScript API ก็จะไม่สามารถเลือก Generative Language API (Gemini) ได้เหมือนกัน

สองภาพนี้บอกทุกอย่างครับ Google บังคับให้ Maps key กับ Gemini key เป็นคนละตัวกันโดยสมบูรณ์แล้ว ไม่ใช่แค่ warning หรือ recommendation แต่เป็น hard restriction ที่ระดับ UI เลย
แต่ Key เก่ายังต้องระวัง
Google แก้ default สำหรับ key ใหม่แล้ว แต่ key เก่าที่สร้างก่อนเดือนกุมภาพันธ์ 2026 ยังเสี่ยงอยู่
ลองนึกดูครับ ถ้าคุณสร้าง key ไว้ตั้งแต่ปี 2022 แล้ว hardcode ไว้ในเว็บ key นั้นอาจยังอยู่ใน state ที่ unrestricted อยู่เลย Google scan หา key ที่หลุดจาก public sources เช่น Common Crawl และ GitHub แต่ถ้า key ของคุณอยู่ใน legacy codebase หรือ internal project ที่ไม่ถูก index ก็อาจยังไม่ได้รับการแก้ไข
วิธีเดียวที่จะรู้แน่คือทดสอบด้วยตัวเอง
ทดสอบ Key ของคุณได้เลย
ผมสร้าง tool สำหรับบทความนี้โดยเฉพาะเลยครับ เป็น HTML ไฟล์เดี่ยว (poc-tester.html) เปิดในเบราว์เซอร์ได้ทันทีโดยไม่ต้องติดตั้งอะไร รองรับทั้งภาษาไทยและอังกฤษ

**🔗** https://github.com/mcca123/Google-API-Key-Gemini-Privilege-Escalation-PoC
tool ยิงไปยัง 4 endpoints พร้อมกัน ได้แก่ Maps Geocode สำหรับยืนยันว่า key ใช้งานได้, Gemini /models ซึ่งเป็น endpoint หลักตามที่ Truffle Security ใช้ทดสอบ, Gemini /files สำหรับตรวจว่า private files หลุดไหม และ /cachedContents สำหรับตรวจ cached data

ถ้า key ไหนตอบกลับ 200 OK แสดงว่ามีช่องโหว่และควรดำเนินการแก้ไขทันทีครับ
จะแก้ได้อย่างไร?
1. Restrict API scope — ไปที่ Google Cloud Console → APIs & Services → Credentials แล้วคลิกที่ key ที่ต้องการแก้ ใต้ “API restrictions” เลือก “Restrict key” แล้วเลือกเฉพาะ API ที่ใช้จริงๆ เช่น Maps JavaScript API โดยไม่รวม Generative Language API
2. Restrict Application — ใต้ “Application restrictions” เลือก “HTTP referrers” แล้วใส่เฉพาะ domain ของเว็บไซต์ที่ใช้ key นั้นจริงๆ วิธีนี้ป้องกันไม่ให้ key ถูกเอาไปยิงจาก domain อื่น แม้จะรู้ค่าแล้วก็ตาม
3. แยก key สำหรับ Gemini — ถ้าต้องการใช้งาน Gemini API ให้สร้าง key ใหม่แยกต่างหากโดยเฉพาะ และ key นั้น ต้องไม่เคยโผล่ใน client-side code ต้องเก็บไว้ใน backend server หรือ Secret Manager เรียกใช้ผ่าน environment variable เท่านั้น
4. Disable API ที่ไม่ใช้ — ตรวจสอบทุก GCP project ว่ามี Generative Language API ถูก enable ไว้หรือไม่ ถ้าไม่ได้ใช้งานจริงให้ disable ออกเลย
ปิดท้าย
สุดท้ายแล้ว ปัญหานี้อาจไม่ได้อยู่ที่ว่า developer คนไหนทำพลาด แต่เป็นเพราะสิ่งที่เราเคยเชื่อว่า “ปลอดภัย” มาตลอด วันหนึ่งมันอาจไม่เป็นแบบนั้นอีกต่อไป และในโลกที่ platform เปลี่ยนเร็วแบบนี้ ความปลอดภัยอาจไม่ใช่แค่ทำตาม documentation แต่คือการตั้งคำถามกับมันอยู่เสมอ
อ้างอิง
- Truffle Security — https://trufflesecurity.com/blog/google-api-keys-werent-secrets-but-then-gemini-changed-the-rules (Feb 25, 2026)
- PoC Tool — https://github.com/mcca123/Google-API-Key-Gemini-Privilege-Escalation-PoC
- Dev stunned by $82K Gemini bill after unknown API key thief goes to town — https://www.theregister.com/2026/03/03/gemini_api_key_82314_dollar_charge/?td=keepreading&utm_source=chatgpt.com (Mar 3, 2026)
- $82,000 in 48 Hours from stolen Gemini API Key. My monthly Usage Is $180. Facing Bankruptcy — https://old.reddit.com/r/googlecloud/comments/1reqtvi/82000_in_48_hours_from_stolen_gemini_api_key_my/ (Feb, 2026)
- Set up the Maps JavaScript API — https://developers.google.com/maps/documentation/javascript/get-api-key?setupProd=configure#make_request
- Firebase security checklist — https://firebase.google.com/support/guides/security-checklist#api-keys-not-secret
- Common Crawl November 2025 Crawl Archive — https://data.commoncrawl.org/crawl-data/CC-MAIN-2025-47/index.html