เสริมพลังความแกร่งของ Biometric Login กับ Flutter — ป้องกันแอปจาก Hacker!

Amorn Apichattanakul
KBTG Life
Published in
3 min readMay 17, 2023
Dash โดนจับแล้ว!!

การที่ผู้พัฒนาเลือกใช้การเข้าแอปด้วย Biometric นั้น ไม่ว่าจะเป็นการสแกนหน้า สแกนนิ้ว หรือสแกนม่านตานั้น ก็นับเป็น Biometric Authentication ทั้งสิ้น ซึ่งเป็นตัวเลือกที่ง่ายสำหรับผู้ใช้งาน ไม่จำเป็นต้องมานั่งจำรหัสหรือพิมพ์ในที่สาธารณะให้คนอื่นเห็นได้ ทั้งนี้ในการติดตั้ง Biometric Authentication ไม่ใช่แค่ว่าผู้พัฒนาไปเอา Flag True/False จาก OS เสร็จแล้วก็อนุญาตผู้ใช้งานให้เข้าแอปเลยนะ ทำแบบนี้ก็หวานหมู Hacker สิ

แน่นอนผมเองก็เคยเป็นหนึ่งในนั้นที่ทำแบบนี้ ก็เราคิดว่า iOS/Android เขาต้องทำมาดีแล้ว ต้องเชื่อได้สิ ปรากฏว่าเราคิดง่ายไป

ใครที่เป็น Flutter Developer แล้วกำลังจะพัฒนาฟีเจอร์ Biometric Authentication อยู่ อยากให้หยุดแป๊บนึง มาอ่านบทความนี้สักหน่อย แล้วค่อยไปคุยกับ Product Owner ว่าถ้าแอปของเรามีข้อมูลเกี่ยวกับการเงินของลูกค้า ไม่ว่าจะระบบผูกบัตรเครดิต หรือ Wallet ใดๆ ก็ตาม ส่วน Security ตรงนี้ของเราควรมีแบบนี้ โดยคอนเซ็ปต์ที่เรากำลังจะพูดถึงกันไม่ได้จำกัดแค่สำหรับ Flutter เท่านั้น แต่ยังสามารถนำไปใช้กับ iOS และ Android ได้อีกด้วยครับ

ทำไมแค่รับ True จาก OS มาแล้วไปต่อไม่ได้ล่ะ? ผมขออ้างอิงจากบทความนี้ที่ว่าด้วยการใช้ Frida Tools ในการ Hack แอปมือถือ แล้ว Inject Flag ให้เป็น True เสมอเวลาเรียก Biometric

ซึ่งแน่นอน Tools นี้ก็สามารถทำกับ Android และ Flutter ได้เหมือนกัน แปลว่าถ้าแอปผูกบัตรเครดิตไว้ Hacker ก็สามารถ Bypass ระบบเข้าไปในแอปได้เลย แต่ต้องเป็นหลังจากที่สามารถเข้า Pin Code ของเครื่องครับ

ทั้งนี้การเพิ่ม Security ส่วนนี้ไม่ได้จำเป็นสำหรับทุกแอปครับ ถ้าคุณมองว่าแอปของคุณไม่มีความเสี่ยงทางด้านข้อมูลส่วนบุคคลต่างๆ ก็ไม่ต้องทำครับ เพราะถึง Hacker แกะแอปไปได้ ผู้ใช้งานก็ไม่มีอะไรเสียหาย แต่ถ้าใครสนใจ อยากเก็บเกี่ยวความรู้เพิ่มเติม สามารถอ่านบทความนี้ต่อได้นะครับ เผื่อเป็นความรู้สำหรับงานหน้าๆ

ในบทความนี้ ผมจะไม่ได้ลงรายละเอียดว่าการทำ Biometric Login แบบธรรมดาต้องทำยังไงบ้าง เนื่องจากหลายบทความเคยมีเล่าไปแล้วแล้ว ผมจะเจาะเฉพาะประเด็นว่าทำยังไงไม่ให้มีปัญหา Security กับการใช้ Biometric Login

คอนเซ็ปต์หลักๆ ของเราก็คือ เวลามี Request Biometric Login เข้ามา เราจะไม่สนใจใดๆ ครับ เอาแค่ Flag มา Trigger ให้ทำงานต่อ ไม่ได้ให้เข้าแอปเลยทันที ผู้ใช้งานจะไม่สามารถเข้าถึงส่วน Financial ด้วยการเข้าผ่าน Biometric Login แต่จะต้องอัพเกรด accessToken จาก Biometric-token ให้มาเป็น Pin-token ครับ เพราะปกติแล้ว Pin ในทางด้าน Security นั้นจะมีความปลอดภัยในการใช้งานมากกว่า Biometric Login เมื่ออัพเกรดแล้ว จึงจะอนุญาตให้ Pin-token นั้นทำธุรกรรมต่างๆ ได้

มาดูแต่ละสเต็ปเลยครับ ว่าต้องทำยังไงกันบ้าง

ขั้นแรกเราจะต้องตรวจสอบก่อนว่าโทรศัพท์มือถือของผู้ใช้งานนั้นสามารถใช้งาน Biometric Login ได้หรือไม่ โดยเช็คว่าเครื่องมือถือนั้นมี Biometric Login ไหม (เครื่องรุ่นใหม่จะมีหมดแล้วครับ) หรือมี Biometric Login แต่ไม่ได้เปิดใช้งานอยู่ ส่วนนี้เราต้องมีการเขียนให้ครอบคลุมทุกสถานการณ์ครับ

ตัว Android นั้นจะมีคอนเซ็ปต์ที่เรียกว่า Weak/strong Biometric Authentication ซึ่งทาง Android ได้อธิบายไว้ตามลิงก์ด้านล่างนี้

ในกลับกัน iOS จะไม่มีคอนเซ็ปต์เหล่านี้ครับ จะมีแค่ว่าเปิดใช้หรือไม่ได้เปิดใช้เท่านั้นเอง

โดยปกติแล้ว Android จะมอง Fingerprint Authentication เป็น Strong Biometric Authentication และ Face/iris Scan เป็น Weak Biometric Authentication แม้จะไม่ใช่ทุกเคสเสมอไป แต่ส่วนใหญ่จะนับแบบนี้ได้ ซึ่งถ้าจะเอาข้อมูลแบบถูกต้องเป๊ะๆ ต้องไปดูที่ Android Compatibility Definition Document (CDD) เขาจะประเมินความเสี่ยงส่วนนี้เอาไว้ว่า Strong คืออะไร และ Weak คืออะไร ตามลิงก์ด้านล่างครับ

จากที่ผมได้คุยกับทางทีม Pen Test มา เขาก็ไม่ได้มีระบุมาเป็นพิเศษนะครับว่าต้องใช้ Strong เพราะสุดท้ายเราก็ไม่ได้เชื่อ Flag ที่มาจากอันนี้อยู่แล้วครับ ต่อให้หลอก Flag ได้ ก็จะมาหลอกเคสที่เรา Handle ไว้ไม่ได้อยู่ดี ดังนั้นแล้วแต่ Product Owner เลยครับว่าอยากใช้ Strong อย่างเดียว หรือทั้ง Weak/Strong คู่กัน ซึ่งถ้าเลือกใช้ Strong อย่างเดียว ก็ต้องมาระวังว่าคนปกติทั่วไปจะเข้าใจไหมว่ามันคืออะไร เพราะขนาดผู้พัฒนาเองก็ยังไม่ทราบรายละเอียดส่วนนี้เท่าไหร่ว่า Android มีการแบ่งประเภทความปลอดภัยของ Biometric Login ไว้ด้วย จึงเป็นเราที่ต้องไปสื่อความหรืออธิบายให้ลูกค้าเพิ่มเติมว่าทำไมถึงให้ใช้สแกนนิ้ว สแกนหน้าห้ามใช้

ในส่วนของ Biometric Authentication ของ Flutter ผมเลือกใช้ local_auth Library

ซึ่งใน Lib สามารถเลือกได้ว่าอยากใช้ Weak หรือ Strong แล้วแต่ Requirement ของงานเลยครับ

ขั้นที่สอง คือให้ใช้วิธี Biometric Storage ซึ่งก็คือ Secure Storage ที่จะสามารถเรียกข้อมูลมาใช้งานได้ก็ต่อเมื่อทำ Biometric Authentication ผ่านแล้วเท่านั้น เพิ่มความมั่นใจอีกขั้นว่าข้อมูลส่วนนี้จะรั่วไหลได้ยากขึ้นไปอีก สามารถอ่านรายละเอียดเกี่ยวกับ Biometric Storage เพิ่มเติมได้ที่ลิงก์นี้ครับ

Android เองก็มีหลักการแบบเดียวกัน เรียกว่า Android Keystore System

ในมุม Security นั้น เราจะมองว่า Client หรือ Mobile Application เชื่อถือไม่ได้ ไม่มีความปลอดภัย ห้ามเชื่อข้อมูลใดๆ จาก Client ทุกประเภท จนกว่าจะมีการยืนยันว่า Client นั้นเป็น Client ที่เรารู้จักจริงๆ และแม้ว่า Client จะส่ง Request มาขอ Login ด้วย Biometric เราก็จะไม่ฟัง 😆 เราต้องมีการเสริมความปลอดภัยด้วย Server-side Authentication อีกชั้น เพื่อตรวจสอบว่า Client ดังกล่าวไม่ได้ถูกดัดแปลงมา

ขั้นที่สาม หลังจากที่ผู้ใช้งานตัดสินใจแล้วว่าจะใช้ Biometric Login สิ่งที่เราต้องทำคือการสร้าง Private Key กับ Key Pair ซึ่งเราสามารถเลือกใช้ cryptography Lib มาช่วยในส่วนนี้

จากนั้นให้เราสร้าง Public Key และ Seed จาก Private Key ส่งไปให้เซิร์ฟเวอร์ครับ เราจะได้เป็น Server Key กลับมา ให้เรานำ Server Key นั้นมารวมเข้ากับ Private Key ของเรา เพื่อสร้าง Shared Key ออกมา โดย Shared Key นี้แหละจะเป็นตัวสำคัญในการเข้ารหัสสำหรับใช้งาน Biometric Login ในอนาคตครับ

และสุดท้าย เราจะต้องเซฟ Shared Key ไว้ในเครื่อง แต่เราจะเซฟด้วยวิธีปกติไม่ได้นะครับ ต้องใช้ Biometric Storage ในการเซฟเท่านั้น ซึ่งหลักการทั้งหมดที่พูดมา คล้ายๆ กับการ Handshake ที่ผมเคยได้เล่าไปบทความก่อนหน้านี้

แต่สิ่งที่ไม่เหมือนคือขั้นตอนสุดท้ายครับ ในบทความนั้นจะให้เซฟใน Secure Storage แต่อันนี้จะให้เซฟใน Biometric Storage แทน

เราจะใช้ Key ที่สร้างขึ้นมานี้ในการ Login ครั้งต่อๆ ไป ซึ่งในการ Login จะมีขั้นตอนดังต่อไปนี้

  1. ถาม Biometric Authentication จากผู้ใช้งาน ตอนที่มีความต้องการจะ Login
  2. ดึง Shared Key ออกมาจาก Biometric Storage หลังจากทำการ Biometric Authentication เรียบร้อยแล้ว
  3. ให้เรียก API เพื่อขอ challengeString จากเซิร์ฟเวอร์ ซึ่งจะเป็น String ชุดนึงที่ถูกสร้างขึ้นมาเฉพาะครั้งเท่านั้น
  4. ให้ใช้ challengeString เพื่อทำการ Encrypt Shared Key ของเราครับ เราจะได้ Key ตัวใหม่เรียกว่า encryptShareKey
  5. ให้ส่ง bodyKey ที่ได้มาจากการ Handshake ครั้งแรกก่อนเข้าแอป ไปพร้อมกับ encryptShareKey เพื่อที่จะเอา accessToken มาใช้

accessToken ที่ได้มานี้ จะขอเรียกว่า Biometric-token แล้วกันนะครับ โดย Token ตัวนี้จะใช้เข้าแอปได้แค่บางส่วนเท่านั้น หลักๆ จะเป็นส่วนที่ไม่เกี่ยวกับข้อมูล Sensitive Data ทำได้เข้าไปดูแอปเฉยๆ ดูข้อมูลทั่วไปเท่านั้น แต่ถ้าส่วนที่ต้องเริ่มจ่ายเงิน โอนเงิน หรือเกี่ยวกับข้อมูล Sensitive จะต้องทำการเปลี่ยน Biometric-token ให้กลายเป็น Pin-token เสียก่อน ด้วยการนำ Biometric-token บวกกับการกด Pin ในแอป ไปแลกกับ Pin-token ครับ

ฟังแล้วกว่าจะทำได้ ดูแล้วงง?! ปวดหัวจัง?! แต่ไม่เป็นไรครับ ตอนเขียนบทความผมก็งง 555 ผมเลยทำเป็น Sample Project ขึ้นมาที่ Github เพื่อใช้คู่กับบทความ สามารถนำไปดูเป็นตัวอย่างประกอบได้ รวมถึงวิดีโอโชว์วิธีการทำงานนี้ครับ

ทั้งหมดนี้ก็เป็นภาพรวมของการทำ Biometric Login ให้ปลอดภัยยิ่งขึ้นครับ ซึ่งวิธีนี้ผ่าน Penetration Testing มาแล้ว สามารถนำไปใช้เป็นแนวทางในการพัฒนาเพื่อปิดช่องโหว่ของการทำ Biometric Login ได้ครับ

อย่าลืมครับ Biometric Login ไม่ใช่แบบง่ายๆ ดู Flag True/False แล้วจบนะครับ

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

--

--

Amorn Apichattanakul
KBTG Life

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