Mobile Security via Flutter — ตอนที่ 3 วิธี Secure API ตอน 1/2

Amorn Apichattanakul
KBTG Life
Published in
3 min readMay 12, 2021

จากบทความครั้งที่แล้วที่ได้เขียนไว้เกี่ยวกับการสร้างความแข็งแกร่งให้กับแอปภายนอก ในบทความนี้เราจะมาพูดถึงการทำให้แอปแข็งแกร่งจากภายใน คือการ Secure API หรือการทำให้ API ปลอดภัยนั่นเอง

เนื่องจากบทความนี้จะค่อนข้างยาว ผมจึงจะขอแบ่งออกเป็น 2 ส่วน ส่วนแรกจะอธิบายถึงคอนเซ็ปต์และการเตรียมตัวก่อนทำการ Secure API ส่วนที่สองจะเป็นวิธีการ Implement บน Flutter ซึ่งจะอยู่ในบทความหน้าครับ มาเริ่มกันด้วย Checklist ที่เราควรจะต้องทำก่อนที่จะมี Secure API โดยที่ส่วนใหญ่จะเป็นทางด้านของ Backend เป็นหลัก ดังนี้

จำเป็น

  1. ให้ใช้ SSL Certificate และรับ HTTPS เท่านั้น ห้ามรับ Request ใดๆ จาก HTTP
  2. ให้ใช้ TLS 1.2 ขึ้นไป เพราะ 1.0, 1.1 เลิกรองรับแล้ว (ref)
  3. ให้ใช้ Unique userID อย่าเอา userID ที่ได้จากพวก SQL มาใช้ตรงๆ นะครับ เช่น อย่าใช้…
userID = 1

แต่ให้ใช้…

userID = C72E77A3D892BA02F2214E3F10

ไม่งั้นเราสามารถโดนยิง userID ได้ง่ายๆ ก็แค่เปลี่ยนตัวเลขไปเรื่อยๆ

4. ให้ล็อคระบบถ้าผู้ใช้งานใส่ Password ผิดเกิน X ครั้ง โดยจำนวนครั้งจะขึ้นอยู่กับ Business Requirement แต่ประมาณ 3–5 ครั้งกำลังดี อย่ามากจนเกินไป เพราะว่าเวลาแฮกเกอร์ Brute Force ตัว Password เราจะได้ป้องกันให้ผู้ใช้งานได้ ไม่เช่นนั้นแฮกเกอร์จะใช้ Dictionary Attack พยายามล็อกอินเข้ามา

5. ให้ระบบมีทำ Session Timeout และ Token จะต้องมีวันหมดอายุใน X ชม โดยจำนวนชั่วโมงจะขึ้นอยู่กับ Business Requirement ถ้าเอาแบบ Secure หน่อยก็ประมาณ 15 นาทีครับ แต่โดยปกติจะเห็นประมาณ 1 วัน

6. ให้ใส่ Pin หรือ Password แบบยากหน่อย ห้ามให้ใส่อิสระ ต้องให้สมดุลสักหน่อยนะครับ อย่ายากเกินไป แต่ก็อย่าให้ง่ายเกิน ใครที่สนใจศึกษาเกี่ยวกับ Pin เพิ่มเติม สามารถอ่านได้ในบทความที่ผ่านมาครับ

7. ป้องกัน Replay Attack ด้วยการไม่อนุญาตให้ใช้ Response เดิมๆ ที่เคยใช้ไปแล้ว ยกตัวอย่างเช่น คุณโอนเงินให้นาย B แล้วแฮกเกอร์สามารถขโมย Response ไปได้ เขาจะใช้ Response เดิมๆ ยิงไปเรื่อยๆ ซึ่งแม้ว่าเราจะ Encrypted Response ไปแล้ว แฮกเกอร์ก็ไม่จำเป็นต้องอ่าน เพราะเขาสามารถนำ Response ไปใช้ซ้ำๆ ได้ เราจึงจำเป็นต้องป้องกันส่วนนี้ครับ

8. การเก็บ Log ใน Backend ควรมีการ Mask ข้อมูลที่ละเอียดอ่อน (Sensitive Data) อย่างที่เคยบอกครับ คนในน่ากลัวกว่าคนนอกอีก เพราะ Developer ไม่ได้อยู่กับโปรเจคตลอดเวลา ถ้าคนในที่รู้ Logic หรือช่องโหว่อยู่แล้วก็สามารถกลับมาโจมตีได้

9. สิ่งที่เป็นพื้นฐานมากๆ แต่หลายคนไม่ได้ทำ คือ 2FA (2 Factor Authentication) เพื่อป้องกัน Source Code หลุดออกไป ทั้งนี้แฮกเกอร์ไม่ได้โจมตีแต่เพียงผู้ใช้งานนะครับ บางที Developer ก็โดนด้วยเหมือนกัน ฉะนั้น Git Account ของคุณจำเป็นต้องใส่ 2FA ด้วยนะครับ

มีก็ดี

1. สามารถตรวจสอบได้ว่ามี Multiple Login สามารถแก้ได้ด้วยการไม่อนุญาตให้ล็อกอินจากหลายๆ ที่ได้ หรือทุกการล็อกอินจะมีการแจ้งผู้ใช้งานอีกที

2. ส่งโนติแจ้งเตือน ด้วย Email/SMS เวลาที่มีการล็อกอินเข้ามาใช้งาน

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

แนวคิดของ Secure API

จากบทความที่ผ่านมา เราได้เรียนรู้กันแล้วว่าไม่มีอะไรป้องกันได้ 100% สิ่งที่เราจะทำกันคือปิดช่องโหว่ให้ได้มากที่สุด

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

Digital Signature

สำหรับเนื้อหาแบบละเอียดๆ สามารถไปอ่านได้ที่ลิงก์ด้านล่าง

แต่ถ้าใครอยากอ่านแบบสั้นๆ ตามมาได้เลยครับ

Credit: https://docs.oracle.com/cd/E19528-01/820-2493/aakfx/index.html

Digital Signature คือการที่เราเข้ารหัสในการส่งระหว่าง Client กับเซิร์ฟเวอร์ นอกจากนั้นเราจะมีการทำ Hash ของ ข้อมูลที่ส่งไปด้วย เพื่อเช็คว่าข้อมูลที่ส่งไปนั้นไม่ได้มีการเปลี่ยนแปลงระหว่างทาง เพราะถ้ามี ตัวเลขของ Hash จะไม่ตรงกับต้นทางที่ Hash เอาไว้ ซึ่งเป็นวิธีที่ได้รับการยอมรับแบบสากล แม้แต่ในบางประเทศอย่างอเมริกาสามารถใช้วิธีนี้เป็นตัวยืนยันในการส่งเอกสารแบบดิจิทัลได้ และมีผลตามกฏหมายเหมือนเซ็นเอกสารด้วยมือ แสดงให้เห็นว่าวิธีนี้รับประกันความปลอดภัยได้จริงๆ

เมื่อเรารู้แล้วว่าปลอดภัย เรามาประยุกต์ใช้กับแอปกัน สำหรับขั้นตอนในการทำ Digital Signature ระหว่างแอปกับ Backend จะเป็นแบบนี้ครับ

1. แลกเปลี่ยน Key

การแลกเปลี่ยน Key คือการที่ทั้งฝ่ายแอปและฝ่าย Backend สร้าง Key ขึ้นมาคนละดอก โดยทั้งคู่จะเก็บ Private Key ไว้กับตัวเอง และจะนำ Public Key มาแลกกัน ทั้ง 2 ฝ่ายจะใช้ Public Key ในการเข้ารหัสเวลาส่งข้อมูลให้กันและกัน และจะใช้ Private Key ที่เก็บไว้ในการถอดรหัส แต่วิธีนี้มีความจุดอ่อนอยู่อย่างนึงคือครั้งแรกสุดที่มีการแลก Key กันนั้นอาจสุ่มเสี่ยงต่อการถูกดักฟัง ฉะนั้นเพื่อความปลอดภัย การเลือกเปลี่ยน Key ครั้งแรกจะต้องใช้การเชื่อมต่อที่ปลอดภัยที่สุด ให้มั่นใจว่าจะไม่ถูกขโมยข้อมูลไป แล้วจะทำยังไงกันดีล่ะ?

ห้ามใช้ WIFI หรือให้ผู้ใช้งานเข้ามายืนยันตัวตนกับเจ้าหน้าที่

เพราะว่าการใช้ WIFI นั้นเป็นการเปิดช่องโหว่ให้สามารถถูกดักฟังได้ เราจึงไม่นับเป็นการเชื่อมต่อที่ปลอดภัย ให้เราไปใช้สัญญาณโทรศัพท์ 3G/4G แทน แม้การใช้ 3G/4G อาจจะไม่ช่วยให้รอดพ้นจากการถูกดักฟังเสียทีเดียว แต่ดักฟังจากคลื่นสัญญาณเหล่านี้เป็นไปได้ยากมากๆ จึงนับว่าเป็นการเชื่อมต่อที่ปลอดภัยที่สุดแล้ว

อีกแบบคือการที่เข้ามายืนยันตัวตนด้วยตัวเองกับคน แม้ว่าระบบบางอย่างดูโบราณก็จริง แต่ก็เป็นอะไรที่แฮกเกอร์ไม่สามารถล้วงข้อมูลได้ ในเมื่อออนไลน์ไม่ปลอดภัย เราก็เลยเลือกใช้ออฟไลน์แทน

สำหรับกระบวนการแลกเปลี่ยน Key นั้นจะใช้ระบบรหัสแบบอสมมาตร หรือ Asymmetric Key ประกอบด้วย Public Key และ Private Key

Private key บนเซิร์ฟเวอร์สามารถบันทึกได้ แต่ Private Key บนแอปควรทำการบันทึกหลังจากที่ Encrypt ไปแล้วเท่านั้นนะครับ และให้ทำการสร้าง deviceID และส่งมาให้ทางเซิร์ฟเวอร์ด้วย เพื่อทางเซิร์ฟเวอร์จะได้มีข้อมูลยืนยันเพิ่มว่าผู้ใช้งานยังเป็นคนเดิมอยู่ deviceID จะเป็นตัวเลข Random อะไรก็ได้ครับ บันทึกลงไปในเครื่องเป็นแค่ตัวเลขยืนยันว่าเครื่องลูกค้าคือเครื่องเดิมอยู่หรือเปล่าเท่านั้นเอง หลังจากที่แลกเปลี่ยน Key กันเสร็จ เราจะนำ Key ที่ได้รับจากเซิร์ฟเวอร์มา Encrypt ข้อมูลทุกครั้งที่จะส่งให้เซิร์ฟเวอร์ ป้องกันไม่ให้แฮกเกอร์ Decrypt ข้อมูลได้ นอกจากจะได้ Private Key จากทั้งคู่เพื่อมาแกะดูข้อมูล จากนั้นเราก็จะสามารถใช้ Insecure Network ได้แล้ว เพราะเหมือนเราได้แลกนามบัตรกัน รู้จักหน้าตากันเป็นที่เรียบร้อย วางใจได้ว่าข้อมูลที่จะส่งมาเป็นข้อมูลที่ทั้งคู่รู้กันเองเท่านั้น

2. เข้ารหัสข้อมูลเวลาส่ง

เมื่อเรามั่นใจแล้วว่า Private Key ถูกเก็บไว้ในที่ปลอดภัย ถึงเวลาที่เราจะเข้ารหัสเวลาส่งข้อมูล โดยเราจะส่งข้อมูล 2 ส่วนไปให้เซิร์ฟเวอร์ อย่างแรกคือเนื้อหาที่ต้องการ อาจจะเป็นพวก JSON, XML หรืออะไรก็ตาม ส่วนที่สองคือ Hashing Signature หรือว่าลายเซ็นต์กำกับว่ามาจากเราจริงๆ

3. วิธีการสร้าง Hashing Signature

Hashing Signature จะเป็นข้อมูลในการยืนยันว่า JSON หรือ Content ที่เราส่งไปให้ไม่ได้ถูกทำการเปลี่ยนแปลง เพราะถ้าถูกเปลี่ยน ค่า Hash ที่ส่งไปจะไม่ตรงกับ Hash ของ JSON อันใหม่ ซึ่งข้อมูลดังกล่าวไม่มีใครสามารถทำเลียนแบบได้ แต่ในการ Hash นี้เราจะมี Nonce และ Timestamp เวลาที่ Hash ไปด้วย

Nonce คือค่า Random ที่ถูกสร้างขึ้นมาจากตัวเลขและตัวอักษร เพื่อทำการป้องกัน Replay Attack เพราะ Nonce จะถูกสร้างขึ้นมาเพื่อใช้งานครั้งเดียว จะนำ Nonce เดิมไปใช้ซ้ำไม่ได้

Timestamp ไว้ใช้คู่กับ Nonce เพื่อตรวจสอบว่า Nonce นี้ใช้กับเวลาเท่าไหร่ เป็นการป้องกัน Replay Attack เช่นกัน

4. Decrypt Body

หลังจากที่เซิร์ฟเวอร์ได้รับข้อมูลจากฝั่ง Mobile แล้ว จะทำการถอดรหัสข้อมูลด้วย Key ที่มีอยู่

5. ตรวจสอบความถูกต้องของข้อมูลด้วยก่อนใช้งาน

หลังจากที่ถอดรหัสข้อมูลออกแล้ว อย่าเพิ่งนำ Body ไปใช้นะครับ ให้ทำการเช็คความถูกต้องของข้อมูลที่ส่งมากับ Signature ก่อน ตรวจสอบค่า Hash ว่า Response ที่ได้ กับค่า Hash ที่ส่งมาใน Header เป็นค่าเดียวกัน ถ้าได้ค่าเดียวกันแปลว่าข้อมูลที่ได้รับถูกต้อง ไม่ได้ถูกดัดแปลงแต่อย่างใด ต่อไปให้นำ Body ไปตรวจสอบค่า Nonce กับ Timestamp ว่าเคยถูกใช้งานไปหรือยัง ถ้ายังก็สามารถนำ Body ไปใช้ได้เลยครับ

อันนี้ก็คือคอนเซ็ปต์คร่าวๆ ของการทำ Digital Signature และวิธีใช้งาน ในบทความหน้าเราจะมาพูดถึงการ Implement ผ่าน Flutter กันครับ

สำหรับชาวเทคคนไหนที่สนใจเรื่องราวดีๆแบบนี้ หรืออยากเรียนรู้เกี่ยวกับ Product ใหม่ๆ ของ KBTG สามารถติดตามรายละเอียดกันได้ที่เว็บไซต์ www.kbtg.tech

--

--

Amorn Apichattanakul
KBTG Life

Google Developer Expert for Flutter & Dart | Senior Flutter/iOS Software Engineer @ KBTG