J2TEAM Security: A must-have extension for Chrome users. Install now!

Tôi đã hack Kickstarter và AirBnb như thế nào?

Tôi đã hack kickstarter thông qua hệ thống Facebook Login như thế nào? Mọi chuyện bắt đầu từ nắm 2013 trong quá trình xây dựng chức năng login với Facebook
Mọi chuyện bắt đầu từ nắm 2013 trong quá trình xây dựng chức năng login với Facebook, tôi đã tìm ra một cách để tấn công vào các hệ thống login với Facebook khác. Để chứng minh phương pháp tấn công của mình là hiệu quả, tôi có test thử phương pháp này với khá nhiều ứng dụng khác, và kết quả là rất nhiều ứng dụng gặp lỗi tương tự. Hai ứng dụng phổ biến nhất trong số đó là AirBnB và Kickstarter.

Sau khi thông báo cho các công ty, đưa ra cách giải quyết và thấy rằng Facebook đã cập nhật trang API docs của họ để nhắc nhở các lập trình viên hãy chú ý tới lỗi này, tôi nghĩ rằng mọi chuyện đã ổn. Nhưng gần đây, trong khi review hộ một người bạn về ứng dụng của anh ta, tôi lại một lần nữa thấy lại bug này.

Thế nên tôi quyết định chia sẻ lại phương pháp tấn công này tại buổi meetup tháng 3 của Ruby Sài Gòn và post lại lên Kipalog để các bạn chưa tham dự buổi meet up lần đó chú ý hơn.

Hai cách cài đặt

Khi bạn bấm vào nút đăng nhập với Facebook trên một ứng dụng di động, ứng dụng này sẽ sử dụng Facebook SDK, gọi tới API của Facebook, để yêu cầu user trên Facebook cho phép ứng dụng của bạn được sử dụng tài khoản Facebook để đăng nhập. Nếu user đồng ý, Facebook API sẽ gọi ngược lại ứng dụng của bạn kèm theo một access_token của Facebook.
Tôi đã hack Kickstarter và AirBnb như thế nào?

Tới đây, tôi sẽ mô tả 2 cách cài đặt phổ biến nhất của các ứng dụng di động cho chức năng này, và các cách tấn công tương ứng.

Sử dụng client để lấy dữ liệu từ Facebook

Tôi đã hack Kickstarter và AirBnb như thế nào?

  1. Đầu tiên, ứng dụng di dộng sẽ sử dụng facebook access_token gọi tới Facebook API
  2. Facebook API trả về dữ liệu với trường user_id của facebook user
  3. Client sẽ sử dụng user_id này để gửi lên server của ứng dụng
  4. Server sẽ kiểm tra trong database để xem có user nào mà facebook_id trùng với user_id được ứng dụng truyền lên hay không? Nếu có thì trả về user đó, nếu không, thì tạo mới user.
  5. Sau đó, server sẽ trả lai access_token cho ứng dụng di động

Cách cài đặt này có gì sai? Hãy cùng xem kịch bản để hacker tấn công như thế nào!
Tôi đã hack Kickstarter và AirBnb như thế nào?
Tại bước thứ 3, attacker gửi tới một facebook_id giả, và trùng với một trong các facebook_id có trong hệ thống của bạn. Khi đó server vẫn sẽ tuân theo các bước thứ 4 và thứ 5 để trả về access_token cho user.

Cách tấn công thật đơn giản, nguyên nhân sâu xa là bởi vì trong cách cài đặt này, chúng ta đã mắc phải một lỗi trong lập trình đó là: Để client validate dữ liệu. Khi nhận được access_token từ Facebook, phía validate dữ liệu là client - ứng dụng mobile. Ứng dụng mobile sau khi validate dữ liệu, có được facebook_id gửi lên server và server tin tưởng vào dữ liệu này. Để login một user, trong trường hợp này tất cả các thông tin bạn cần chỉ là một facebook_id - tức một số 64 bit.

Vậy làm sao để có thể sửa lỗi này? Câu trả lời đó là, hãy để việc validate dữ liệu cho server. Chúng ta hãy cùng xem cách cài đặt thứ hai.

Sử dụng server để lấy dữ liệu từ Facebook

Tôi đã hack Kickstarter và AirBnb như thế nào?
  1. Ngay khi nhận được access_token từ Facebook, ứng dụng di động sẽ gửi token này lên server
  2. Server sử dụng access_token này để gọi API từ Facebook, cụ thể ở đây là API https://graph.facebook.com/me
  3. Facebook trả về dữ liệu có chứa facebook_id của user
  4. Server sẽ kiểm tra trong database để xem có user nào mà facebook_id trùng với user_id được ứng dụng truyền lên hay không? Nếu có thì trả về user đó, nếu không, thì tạo mới user.
  5. Sau đó, server sẽ trả lai access_token cho ứng dụng di động

Vậy với cách cài đặt này, attacker có thể tấn công như nào?
Tôi đã hack Kickstarter và AirBnb như thế nào?
Để tấn công, attacker chỉ cần gửi lên server một valid access token của user từ Facebook. access_token này có thể lấy từ một ứng dụng khác. Ví dụ, trong kịch bản tấn công của mình, tôi lấy access_token từ Facebook của ứng dụng Quora, và gửi tới server của Kickstarter và AirBnB. Kết quả cả 2 servers kể trên đều nhầm tưởng đó là access_token đúng, và cho tôi đăng nhập vào hệ thống.
Thử tưởng tượng, bạn cũng cho phép một ứng dụng thứ ba nào đó sử dụng tài khoản Facebook của bạn, và ứng dụng thứ ba đó lưu lại access_token của bạn, thì ứng dụng này có thể có được tài khoản của bạn ở bất cứ nơi nào bạn sử dụng Facebook để login. Thật đáng sợ phải không?

Lỗi sai lớn nhất trong cách cài đặt này đó là Không kiểm tra dữ liệu nhận được xem có phải từ nguồn tin tưởng hay không? Bất cứ khi nào bạn nhận được dữ liệu, bạn đều phải kiểm tra xem dữ liệu đó có phải là từ một nguồn đáng tin cậy không? Điều này cũng giống như trong thế giới thật, đâu phải ai nói với bạn điều gì, bạn cũng tin đúng không?

Để sửa lại lỗi này, chúng ta cần thêm một bước kiểm tra xem access_token có phải là access_token do ứng dụng chúng ta sinh ra hay không, bằng cách sử dụng API của facebook GET /debug_token?input_token={input-token}&access_token={access-token}

Tổng kết

Hai cách thức tấn công kể trên không chỉ đúng với Facebook API, mà còn có thể áp dụng với bất cứ hệ thống OAuth nào. Vì thế, hãy ghi nhớ 2 điều:

  1. Luôn luôn validate lại dữ liệu từ client gửi lên
  2. Phải kiểm tra xem dữ liệu có phải từ nguồn tin cậy hay không.

Cập nhật

Facebook API giờ đã thay đổi cách thức, giờ đây khi bạn gọi API /me với access_token, Facebook sẽ trả về facebook_id là id của ứng dụng, chứ không phải global id nữa, nên hai cách tấn công kể trên sẽ phải thay đổi đi đôi chút. Nhưng 2 điều cần lưu ý kể trên vẫn nên được áp dụng với mọi API.

Tác giả: kiennt - Kipalog.
Leader at J2TEAM. Website: https://j2team.dev/

Đăng nhận xét

Cảm ơn bạn đã đọc bài viết!

- Bạn có gợi ý hoặc bình luận xin chia sẻ bên dưới.

- Hãy viết tiếng Việt có dấu nếu có thể!