ปกป้องแอปพลิเคชัน: เมื่อการเชื่อมโยง OAuth ของ Spotify บน Android ถูกหลบเลี่ยงได้ง่ายๆ


ปกป้องแอปพลิเคชัน: เมื่อการเชื่อมโยง OAuth ของ Spotify บน Android ถูกหลบเลี่ยงได้ง่ายๆ

ความลับของการเข้าถึงบัญชี Spotify โดยไม่ได้รับอนุญาตบน Android

เคยสงสัยไหมว่าแอปพลิเคชันต่างๆ เชื่อมต่อกับบริการอย่าง Spotify ได้อย่างไร? โดยทั่วไปแล้ว กระบวนการนี้เรียกว่า OAuth มันคือมาตรฐานที่ช่วยให้แอปหนึ่ง (เช่น แอปฟังเพลงของบุคคลที่สาม) สามารถขอสิทธิ์เข้าถึงข้อมูลผู้ใช้จากอีกบริการหนึ่ง (เช่น Spotify) ได้ โดยไม่ต้องรู้รหัสผ่านของผู้ใช้ และนี่คือจุดที่ความปลอดภัยสำคัญมาก

เมื่อแอปพลิเคชันบน Android ต้องการเชื่อมต่อกับ Spotify เพื่อเข้าถึงเพลงหรือเพลย์ลิสต์ของผู้ใช้ มันจะต้องผ่านขั้นตอนการอนุญาตที่ซับซ้อนกว่าที่เราคิดเล็กน้อย ปกติแล้ว Spotify มีกลไกป้องกันที่ค่อนข้างฉลาดเพื่อยืนยันตัวตนของแอปที่ร้องขอ นั่นคือการตรวจสอบทั้ง ชื่อแพ็กเกจ และ ลายนิ้วมือ SHA-1 ของแอป เพื่อให้แน่ใจว่ามีเพียงแอปที่ถูกต้องตามที่ลงทะเบียนไว้เท่านั้นที่ได้รับอนุญาต

นั่นคือสิ่งที่ควรจะเป็น

การทำงานที่ผิดพลาด: จุดอ่อนในกระบวนการยืนยันตัวตน

ปัญหาที่เราจะพูดถึงอยู่นี้เกิดขึ้นจากรายละเอียดเล็กๆ น้อยๆ ในการเขียนโค้ด ซึ่งกลับกลายเป็นช่องโหว่ขนาดใหญ่ ลองนึกภาพว่ามีแอปพลิเคชันหนึ่งที่ถูกต้องตามกฎหมาย (เรียกว่า “แอปแท้”) ต้องการให้ผู้ใช้ล็อกอิน Spotify ผ่านแอปของตัวเอง

แอปแท้จะเรียก Activity ของ Spotify เพื่อเริ่มกระบวนการล็อกอินและขอสิทธิ์การเข้าถึง ที่นี่แหละคือจุดเปลี่ยนสำคัญ โดยทั่วไปแล้ว การเรียก Activity ระหว่างแอปด้วยกัน ควรใช้คำสั่ง startActivityForResult() เพื่อให้แอปที่เรียกไปนั้นรู้ว่าผลลัพธ์สุดท้ายควรส่งกลับมาหาตัวเองเท่านั้น

แต่ในกรณีนี้ Spotify ใช้แค่ startActivity() ซึ่งหมายความว่า Activity ที่ถูกเรียก (ในที่นี้คือหน้าล็อกอินของ Spotify) จะไม่ได้ผูกมัดผลลัพธ์ของมันกลับไปหาแอปที่เรียกโดยตรง

แผนการอันแยบยล: แอปอันตรายฉกฉวยโอกาส

เมื่อ Spotify ใช้ startActivity() แทน startActivityForResult() ก็เกิดช่องโหว่ขึ้นทันที แอปพลิเคชันอันตราย (เรียกว่า “แอปอันธพาล”) สามารถใช้ประโยชน์จากช่องโหว่นี้ได้อย่างง่ายดาย โดยไม่จำเป็นต้องมีสิทธิ์พิเศษใดๆ บนเครื่องเลยแม้แต่น้อย

แอปอันธพาลสามารถสร้าง Intent Filter ขึ้นมา เพื่อดักจับการตอบสนองจาก Spotify ในกรณีที่แอปแท้เริ่มกระบวนการล็อกอิน และ Spotify ส่ง Authorization Code กลับมา แต่อย่างที่บอกไป การส่งคืนนี้เป็นแบบ “Implicit Intent” ซึ่งหมายความว่าใครก็ตามที่ตั้งค่า Intent Filter ดักไว้ได้ ก็สามารถรับโค้ดนั้นไปได้

นี่แหละคือปัญหาใหญ่ แอปอันธพาลไม่ได้พยายามปลอมตัวเป็นแอปแท้ ไม่ได้พยายามเลี่ยงการตรวจสอบชื่อแพ็กเกจหรือลายนิ้วมือ SHA-1 แต่มันรอแค่จังหวะที่แอปแท้เริ่มกระบวนการกับ Spotify แล้ว ดักจับโค้ด ที่ Spotify ส่งกลับมาเมื่อผู้ใช้ล็อกอินสำเร็จ

ผลกระทบและความเสียหายที่เกิดขึ้น

ด้วยวิธีนี้ แอปอันธพาลก็สามารถ สวมรอย เป็นแอปแท้ได้อย่างสมบูรณ์แบบ มันจะได้รับ Authorization Code ที่ควรจะส่งไปให้แอปแท้ และสามารถนำโค้ดนี้ไปแลกเปลี่ยนเป็น Access Token เพื่อเข้าถึงบัญชี Spotify ของผู้ใช้ได้โดยไม่ได้รับอนุญาต

ลองคิดดูสิ แค่ติดตั้งแอปที่ดูเหมือนไม่มีพิษมีภัย ผู้ใช้ก็อาจตกเป็นเหยื่อของการเข้าถึงข้อมูล Spotify ส่วนตัวโดยไม่รู้ตัว ความผิดพลาดเล็กๆ ในการเลือกใช้ startActivity() แทน startActivityForResult() ทำให้กลไกความปลอดภัยอันซับซ้อนของ OAuth กลายเป็นเรื่องไร้ค่าไปในทันที

ทางแก้ไขปัญหาในเรื่องนี้จึงค่อนข้างตรงไปตรงมา นั่นคือการเปลี่ยนมาใช้ startActivityForResult() เพื่อให้แน่ใจว่าการตอบสนองจาก Spotify จะถูกส่งกลับไปยังแอปที่ร้องขออย่างถูกต้องเท่านั้น นี่เป็นบทเรียนสำคัญสำหรับนักพัฒนาแอปทุกคนเกี่ยวกับการจัดการข้อมูลที่ละเอียดอ่อนระหว่างแอปพลิเคชัน และความสำคัญของการเลือกใช้ API ที่เหมาะสมเพื่อปกป้องผู้ใช้งาน