Ứng dụng Expo hỏng HTTP trên Android 9: là cleartext, không phải VPN
Bản build Expo gọi một API HTTP thường bị hỏng trên Android 9 trở lên. Đường hầm không có lỗi: cờ cleartext thuộc về cấu hình build.
Bạn phát hành bản build mới, chuyển sang VPN, và đúng màn hình đó không tải được nữa. Trên Android 9 trở lên, lời giải thích phổ biến hơn lại nhàm chán hơn: nền tảng từ chối HTTP thường cho các ứng dụng nhắm tới API 28 trở lên, còn VPN chỉ thay đổi vừa đủ ngữ cảnh để lộ ra điều đó. Lỗi bạn thấy phụ thuộc vào ứng dụng khách HTTP, nên nó hiếm khi nói cleartext.
Sự cố này thực chất là gì
Từ Android 9, nền tảng chặn cleartext theo mặc định ngay khi ứng dụng nhắm tới cấp API 28 trở lên. Yêu cầu tới một địa chỉ HTTP thường bị nền tảng từ chối trước khi một gói tin rời khỏi thiết bị. Bạn thấy lỗi nào là tùy thư viện HTTP: khi thì lỗi mạng chung, khi thì hết thời gian chờ, khi thì thông báo gọi đích danh cleartext. Điều nó không bao giờ làm là đến được máy chủ của bạn. Android ghi lại mặc định và phương án thay thế giới hạn theo tên miền trong hướng dẫn cấu hình bảo mật.
Trình duyệt trên cùng thiết bị vẫn tải được trang, và đó là manh mối mà hầu hết mọi người bỏ qua. Trình duyệt không chịu chính sách bảo mật mạng của ứng dụng bạn.
Vì sao VPN bị đổ lỗi
Thường có ba thứ thay đổi cùng lúc. Ứng dụng có thể phân giải một tên máy chủ khác sau khi VPN kết nối, thiết bị có thể là máy mới với bản build mới hơn, hoặc chính bản build đã chuyển sang cấp API đích kích hoạt mặc định. VPN thì nhìn thấy được còn SDK đích thì không, nên VPN nhận phiếu.
So sánh cấp đích của bản build cũ và mới trước khi chạm vào cấu hình mạng. Ứng dụng nhắm tới 27 hoặc thấp hơn được miễn, và điều đó giải thích mọi báo cáo kiểu «máy cũ của tôi vẫn chạy».
Cờ của Expo thực sự rơi vào đâu
Trong một dự án Expo được quản lý, việc thêm cài đặt vào app.json không chỉnh sửa manifest Android, vì manifest do prebuild và các bản build phát triển tạo ra. Chính plugin cấu hình là thứ ghi cài đặt ở giai đoạn đó. Đường được hỗ trợ là expo-build-properties, được cấu hình trong cấu hình ứng dụng với tùy chọn cleartext dưới android.
{
"plugins": [
["expo-build-properties", {
"android": { "usesCleartextTraffic": true }
}]
]
}Đoạn mã chỉ đặt tùy chọn plugin; manifest được tạo sau đó. Chạy một prebuild hoặc một bản build ứng dụng khách phát triển mới, rồi trước khi kiểm thử lại hãy kiểm tra AndroidManifest.xml được tạo để tìm android:usesCleartextTraffic, vì chỉ tải lại bằng JS sẽ giữ manifest cũ. Khớp phiên bản plugin với Expo SDK mà dự án chạy. Tùy chọn plugin thay đổi giữa các bản phát hành, và một đoạn mã sao chép từ SDK khác là nguồn đáng tin của việc không làm gì một cách âm thầm.
Luồng bare và lựa chọn hẹp hơn
Với bare React Native, tương đương là android:usesCleartextTraffic trên phần tử application, hoặc cấu hình bảo mật mạng chỉ cho phép cleartext với các tên miền được nêu. Nên chọn dạng giới hạn theo tên miền, vì nó cho phép API nội bộ và để mọi thứ khác trên HTTPS. Nó cũng ghi lại danh sách ngoại lệ của chính mình, và đó chính là phần mà người đánh giá sẽ hỏi.
Không cách nào trong hai cách thay đổi mặc định của nền tảng cho bất cứ thứ gì bạn không nêu tên.
Trước hết hãy chứng minh từ nhật ký thiết bị
Trước khi sửa cấu hình, hãy lấy đúng lỗi. adb logcat trên thiết bị đã kết nối cho thấy nền tảng từ chối cleartext và nêu tên thành phần đã gây ra nó. Một socket bị từ chối, một cái tên không phân giải được hay một cú bắt tay TLS thất bại chỉ về nơi hoàn toàn khác, và bật cleartext chỉ làm ứng dụng yếu đi một cách vô ích.
Sau đó giữ môi trường thật trung thực. Cleartext chấp nhận được cho một điểm cuối phòng thí nghiệm không thể cung cấp TLS, và chỉ trong khoảng thời gian ngắn nhất bạn có thể lên kế hoạch. Nếu API có thể kết thúc TLS bên trong mạng riêng, hãy đặt chứng chỉ vào kho tin cậy của thiết bị và để cleartext tắt, vì đường hầm chỉ mã hóa đường đi tới lối ra của nó và không gì xa hơn.
Khi điểm cuối trả lời qua HTTPS, hãy bỏ quyền, build lại và kiểm thử trên VPN và trên Wi-Fi thường trong cùng một phiên. Việc phân giải tên có thể khác nhau giữa hai đường đi đó, và chỉ có cặp đó mới cho bạn biết bên nào nói đúng.