Play Integrity API là gì? Cách chặn app bị crack, chạy trên máy giả lập và cài từ nguồn ngoài
Bạn đầu tư nhiều tháng xây một ứng dụng có gói trả phí, rồi một ngày phát hiện bản mod của chính app mình đang được phát tán trên các diễn đàn, mở khóa toàn bộ tính năng VIP mà không tốn đồng nào. Hoặc bạn thấy hàng nghìn tài khoản đăng ký mới trong một đêm, tất cả đều đến từ cùng một dải IP và chạy trên trình giả lập. Đây là hai bài toán mà Play Integrity API được sinh ra để giải quyết.
Play Integrity API là dịch vụ do Google cung cấp, cho phép ứng dụng của bạn hỏi hệ thống Google ba câu hỏi và nhận về câu trả lời có chữ ký số không thể giả mạo: bản app đang chạy có phải bản gốc từ Google Play không, thiết bị đang chạy có đáng tin không, và tài khoản Google đang dùng có thực sự sở hữu giấy phép cài app này không.
1. Play Integrity API thay thế cho SafetyNet Attestation
Trước đây, cách kiểm tra tính toàn vẹn thiết bị phổ biến nhất là SafetyNet Attestation API. Google đã dừng nhận đăng ký mới cho SafetyNet và tắt dần dịch vụ này theo lộ trình nhiều giai đoạn, chuyển toàn bộ sang Play Integrity API. Nếu dự án của bạn còn dùng SafetyNet, đây là khoản nợ kỹ thuật cần trả sớm chứ không phải việc để dành.
| Tiêu chí | SafetyNet Attestation (cũ) | Play Integrity API (hiện tại) |
|---|---|---|
| Trạng thái | Đã ngừng nhận dự án mới và tắt dần | Đang được phát triển và mở rộng |
| Kiểm tra tính toàn vẹn thiết bị | Có (basicIntegrity và ctsProfileMatch) | Có, chi tiết hơn với nhiều mức phán quyết |
| Kiểm tra bản app có bị sửa đổi không | Chỉ qua so khớp thủ công dấu vân tay APK | Có sẵn, so với bản Google Play đang phân phối |
| Kiểm tra giấy phép tài khoản | Không, phải dùng Licensing Verification riêng | Có, tích hợp sẵn trong cùng một lần gọi |
| Chống tấn công phát lại (replay attack) | Phải tự xử lý nonce | Có cơ chế nonce và requestHash tích hợp |
2. Ba nhóm phán quyết Play Integrity API trả về
Kết quả trả về là một token đã ký, sau khi giải mã sẽ cho ra ba nhóm thông tin. Hiểu đúng ý nghĩa từng nhóm là điều kiện bắt buộc để không chặn nhầm người dùng hợp lệ.
2.1. appIntegrity: bản app đang chạy có phải bản gốc không
- PLAY_RECOGNIZED: app đang chạy đúng là bản do Google Play phân phối, chưa bị sửa đổi. Đây là trạng thái bạn mong muốn.
- UNRECOGNIZED_VERSION: app có đúng package name nhưng phần nội dung không khớp với bất kỳ bản nào Google Play từng phân phối. Đây chính là dấu hiệu của bản mod, bản crack, hoặc đơn giản là bản debug bạn tự build.
- UNEVALUATED: Google không đánh giá được, thường vì thiết bị không đáng tin ở mức cơ bản.
2.2. deviceIntegrity: thiết bị đang chạy có đáng tin không
- MEETS_DEVICE_INTEGRITY: đây là một thiết bị Android thật, có dịch vụ Google, đã vượt qua bộ kiểm thử tương thích. Mức tiêu chuẩn cho phần lớn app.
- MEETS_BASIC_INTEGRITY: có dấu hiệu là thiết bị Android nhưng không đạt đủ điều kiện của mức trên. Máy đã root, máy chạy ROM tùy biến hoặc một số máy cũ hay rơi vào nhóm này.
- MEETS_STRONG_INTEGRITY: mức cao nhất, có thêm bảo chứng từ phần cứng và hệ thống khởi động. Chỉ nên yêu cầu mức này cho các nghiệp vụ cực nhạy cảm như ngân hàng.
- MEETS_VIRTUAL_INTEGRITY: đang chạy trong môi trường ảo hóa được Google công nhận, ví dụ trình giả lập Android Studio. Đây là mức giúp bạn phân biệt máy ảo hợp lệ với máy ảo lậu.
- Trường rỗng, không có nhãn nào: đây là tín hiệu xấu nhất, thường gặp ở máy đã bị can thiệp sâu hoặc trình giả lập tự chế.
2.3. accountDetails: tài khoản có giấy phép cài app không
- LICENSED: tài khoản Google này đã cài hoặc mua app từ Google Play một cách hợp lệ.
- UNLICENSED: app có mặt trên máy nhưng tài khoản không có lịch sử cài đặt hợp lệ từ cửa hàng. Đây là dấu hiệu điển hình của app tải từ trang chia sẻ APK lậu.
- UNEVALUATED: không đánh giá được, thường do các trường thông tin phía trên đã không đạt.
3. Kiến trúc triển khai đúng chuẩn: vì sao phải xác thực ở máy chủ
Đây là phần bị làm sai nhiều nhất và cũng là phần quyết định toàn bộ giá trị của Play Integrity API.
Luồng đúng gồm bốn bước:
- Máy chủ của bạn sinh ra một chuỗi ngẫu nhiên dùng một lần, gọi là nonce, và gửi xuống cho app.
- App gọi Play Integrity API kèm theo nonce đó, nhận về một token đã được Google ký.
- App gửi token này lên máy chủ của bạn, không tự đọc, không tự quyết định gì cả.
- Máy chủ gọi tới Google Play Developer API để giải mã token, đối chiếu nonce, kiểm tra tên gói ứng dụng, rồi mới ra quyết định cho phép hay từ chối.
Sai lầm phổ biến là để chính app giải mã token và tự quyết định. Cách làm này vô nghĩa hoàn toàn, vì kẻ tấn công đã kiểm soát toàn bộ mã nguồn phía client, họ chỉ cần sửa lại đúng một câu lệnh if là mọi lớp kiểm tra biến mất. Nguyên tắc cốt lõi: kết quả kiểm tra phải được diễn giải ở nơi kẻ tấn công không chạm tới được, tức là máy chủ của bạn.
Sai lầm thứ hai là bỏ qua nonce. Không có nonce, kẻ tấn công có thể lấy một token hợp lệ từ thiết bị sạch, lưu lại, rồi phát lại token đó mãi mãi từ môi trường đã bị can thiệp.
4. Standard request và Classic request: chọn loại nào
| Tiêu chí | Standard request | Classic request |
|---|---|---|
| Độ trễ | Vài trăm mili giây, có bước làm nóng trước | Cao hơn đáng kể, thường vài giây |
| Chi phí tài nguyên trên thiết bị | Thấp, dùng lại kết quả đã lưu đệm | Cao, tính toán lại từ đầu mỗi lần |
| Hạn mức gọi | Rộng rãi, phù hợp gọi thường xuyên | Hạn mức chặt, cần xin nâng nếu vượt |
| Phù hợp với | Kiểm tra định kỳ trong luồng sử dụng bình thường | Các hành động giá trị cao, hiếm khi xảy ra |
| Chống replay | Dùng requestHash | Dùng nonce do bạn tự sinh |
Nguyên tắc chọn trong thực tế: dùng Standard request cho mọi kiểm tra thường xuyên như mở app, vào màn hình chính, gọi API dữ liệu. Dành Classic request cho những khoảnh khắc đắt giá và hiếm gặp như hoàn tất giao dịch lớn, rút tiền, hoặc nhận thưởng có giá trị. Gọi Classic request ở mọi màn hình là cách nhanh nhất để cháy hạn mức và làm app chậm đi thấy rõ.
5. Đoạn mã tối thiểu phía Android
val manager = IntegrityManagerFactory.createStandard(context)
// Bước làm nóng, gọi sớm khi app khởi động
val tokenProvider = manager.prepareIntegrityToken(
PrepareIntegrityTokenRequest.builder()
.setCloudProjectNumber(CLOUD_PROJECT_NUMBER)
.build()
)
// Khi cần kiểm tra một hành động cụ thể
val requestHash = sha256(userId + actionName + serverNonce)
tokenProvider.request(
StandardIntegrityTokenRequest.builder()
.setRequestHash(requestHash)
.build()
).addOnSuccessListener { response ->
// KHÔNG tự giải mã ở đây, gửi thẳng lên máy chủ
sendToBackend(response.token())
}
Điểm cần nhấn mạnh trong đoạn mã trên là dòng comment cuối cùng. App chỉ làm nhiệm vụ chuyển tiếp token, mọi logic quyết định nằm ở phía máy chủ.
6. Bảng chiến lược phản ứng theo từng kết quả
Nhận được phán quyết rồi thì làm gì tiếp? Đây là nơi phân biệt một triển khai chín chắn với một triển khai gây hại cho chính sản phẩm của bạn.
| Kết quả nhận được | Phản ứng nên làm | Phản ứng KHÔNG nên làm |
|---|---|---|
| Mọi thứ đều đạt | Cho dùng bình thường | Không có gì |
| UNRECOGNIZED_VERSION | Hiện hộp thoại lịch sự mời người dùng cài lại app từ Google Play, kèm nút mở thẳng trang cửa hàng | Thoát app đột ngột không giải thích |
| UNLICENSED | Giới hạn tính năng trả phí, mời mua chính thức | Xóa dữ liệu người dùng |
| Chỉ đạt MEETS_BASIC_INTEGRITY | Cho dùng nhưng chặn các nghiệp vụ nhạy cảm, ghi log để phân tích | Chặn hoàn toàn, vì rất nhiều người dùng thật đang chạy máy root hoặc ROM tùy biến |
| Trường phán quyết rỗng | Đưa vào diện rủi ro cao, tăng cường xác thực bổ sung | Coi như lỗi hệ thống rồi cho qua |
| Gọi API thất bại vì mất mạng | Cho phép dùng offline có giới hạn, thử lại sau | Khóa app, vì đây là lỗi hạ tầng chứ không phải gian lận |
7. Kết hợp Play Integrity với các lớp bảo vệ khác
Play Integrity API là một lớp, không phải toàn bộ hệ thống phòng thủ. Một sản phẩm có doanh thu thật nên xếp chồng nhiều lớp:
- Xác minh giao dịch phía máy chủ: mọi giao dịch In-App Purchase phải được xác thực lại bằng Google Play Developer API trước khi cấp quyền lợi, không bao giờ tin vào kết quả client trả về. Xem bài tích hợp Google Play Billing SDK v6.
- Theo dõi hoàn tiền gian lận: kết hợp với Voided Purchases API để thu hồi quyền lợi của những giao dịch đã bị hoàn tiền, chi tiết trong bài chống gian lận hoàn tiền bằng Google Play Developer API.
- Làm rối mã nguồn: bật R8 với cấu hình tối ưu để tăng chi phí dịch ngược, xem bài tối ưu dung lượng AAB APK với R8.
- Giới hạn tần suất phía máy chủ: chặn theo tài khoản và theo thiết bị, vì kẻ tấn công có tổ chức luôn tìm được cách vượt qua từng lớp riêng lẻ.
8. Khi nào KHÔNG nên dùng Play Integrity API
Đây là phần mà tài liệu tiếp thị của mọi nhà cung cấp đều bỏ qua, nhưng nó quyết định việc bạn có làm hỏng sản phẩm của mình hay không.
- App miễn phí hoàn toàn, không có dữ liệu nhạy cảm: chi phí triển khai và rủi ro chặn nhầm lớn hơn lợi ích thu được. Một app đọc tin tức không cần biết máy người dùng có root hay không.
- App phân phối ngoài Google Play: phán quyết về giấy phép và bản app sẽ luôn báo không đạt, vì hệ thống đối chiếu với dữ liệu của cửa hàng. Nếu bạn phát hành song song trên nhiều kho ứng dụng, hãy tách biến thể build và chỉ bật kiểm tra cho biến thể Google Play.
- App phục vụ thị trường có tỷ lệ máy root và ROM tùy biến cao: chặn cứng ở mức thiết bị có thể khiến bạn mất một phần đáng kể người dùng thật. Hãy ghi log trước trong vài tuần để đo tỷ lệ thực tế rồi mới quyết định ngưỡng chặn.
- App bắt buộc chạy offline: Play Integrity cần kết nối mạng để lấy phán quyết. Ứng dụng dùng trong môi trường không có internet ổn định sẽ liên tục rơi vào trạng thái không đánh giá được.
- Bạn chưa có backend: nếu toàn bộ logic nằm ở client, việc tích hợp Play Integrity chỉ tạo cảm giác an toàn giả. Hãy dựng máy chủ xác thực trước rồi mới tính tới bước này.
9. Quy trình 5 bước triển khai không làm hỏng trải nghiệm
- Giai đoạn quan sát: tích hợp API nhưng chỉ ghi log, không chặn bất kỳ ai. Chạy tối thiểu hai tuần để có mẫu số liệu đủ lớn.
- Phân tích phân bố phán quyết: xem bao nhiêu phần trăm người dùng thật đang rơi vào từng nhóm. Nếu tỷ lệ không đạt vượt quá vài phần trăm, ngưỡng bạn định đặt là quá chặt.
- Bật chặn cho nghiệp vụ hẹp nhất trước: chỉ chặn ở đúng một hành động giá trị cao, không chặn ở màn hình khởi động.
- Phát hành dần bằng Staged Rollout: bắt đầu từ 5 phần trăm người dùng và theo dõi chỉ số gỡ cài đặt cùng điểm đánh giá, tham khảo bài Staged Rollout trên Google Play.
- Chuẩn bị sẵn công tắc tắt từ xa: đặt cờ bật tắt trong cấu hình từ xa để có thể vô hiệu hóa việc chặn ngay lập tức nếu số liệu xấu đi, không cần chờ duyệt bản cập nhật.
Kết luận
Play Integrity API không phải là lá chắn tuyệt đối và cũng không nên được kỳ vọng như vậy. Giá trị thật của nó là nâng chi phí tấn công lên đủ cao để phần lớn kẻ crack nghiệp dư bỏ cuộc, đồng thời cho bạn dữ liệu để nhận diện các luồng gian lận có tổ chức. Ranh giới giữa một triển khai tốt và một triển khai gây hại nằm ở chỗ bạn có xác thực token ở máy chủ hay không, và bạn có kiên nhẫn quan sát số liệu trước khi bật chặn hay không.
Nếu bạn đang xây dựng app có doanh thu và cần tư vấn kiến trúc bảo vệ từ khâu thanh toán tới khâu phân phối, Uwmee Software nhận đồng hành từ giai đoạn thiết kế hệ thống. Bài liên quan nên đọc: Google Play chặn APK và lộ trình bắt buộc AAB cùng mô hình Hybrid Monetization kết hợp AdMob và In-App Purchase.