اپلیکیشن Expo در اتصال HTTP روی Android 9 شکست میخورد: مقصر cleartext است، نه VPN
یک build از Expo که یک API سادهی HTTP را فراخوانی میکند، روی Android 9 و بالاتر شکست میخورد. تونل بیگناه است: پرچم cleartext جایاش در پیکربندی build است.
یک build جدید منتشر کردید، به VPN رفتید و همان صفحه از کار افتاد. در Android 9 و بالاتر توضیح رایجتر خستهکنندهتر است: پلتفرم HTTP ساده را برای برنامههایی که API 28 یا بالاتر را هدف میگیرند رد میکند، و VPN فقط بهاندازهای زمینه را عوض کرد که این موضوع آشکار شود. خطایی که میبینید به کلاینت HTTP بستگی دارد، به همین دلیل چنان کم پیش میآید که صریحاً cleartext بگوید.
این شکست در واقع چیست
از Android 9 به بعد، پلتفرم بهطور پیشفرض cleartext را مسدود میکند، بهمحض اینکه برنامه سطح API 28 یا بالاتر را هدف بگیرد. درخواست به یک نشانی سادهی HTTP پیش از آنکه حتی یک بسته از دستگاه خارج شود، توسط پلتفرم رد میشود. اینکه کدام خطا را میبینید به کتابخانهی HTTP بستگی دارد: گاهی یک شکست عمومی شبکه، گاهی پایان مهلت، گاهی پیامی که cleartext را بیپرده نام میبرد. کاری که هرگز نمیکند این است که به سرور شما برسد. Android پیشفرض و جایگزین محدود به دامنه را در راهنمای پیکربندی امنیت مستند کرده است.
مرورگر روی همان دستگاه هنوز میتواند صفحه را بارگذاری کند، و این همان سرنخی است که بیشتر مردم از دست میدهند. مرورگرها تابع سیاست امنیتی شبکهی برنامهی شما نیستند.
چرا VPN سرزنش میشود
معمولاً سه چیز همزمان تغییر میکند. ممکن است برنامه پس از اتصال VPN نام میزبان دیگری را دریافت کند، دستگاه ممکن است نو و با build تازهتر باشد، یا خود build به سطح API هدفی جابهجا شده باشد که پیشفرض را فعال میکند. VPN دیده میشود و SDK هدف دیده نمیشود، پس تیکت به VPN میرسد.
پیش از دست زدن به پیکربندی شبکه، سطوح هدف build قدیمی و جدید را مقایسه کنید. برنامهای که 27 یا پایینتر را هدف میگیرد معاف است، و همین همهی گزارشهای «روی گوشی قدیمی من کار میکند» را توضیح میدهد.
پرچم Expo واقعاً کجا مینشیند
در یک پروژهی مدیریتشدهی Expo، افزودن یک تنظیم به app.json مانیفست Android را ویرایش نمیکند، چون prebuild و buildهای توسعه هستند که مانیفست را تولید میکنند. افزونهی پیکربندی همان چیزی است که تنظیم را در آن مرحله مینویسد. مسیر پشتیبانیشده expo-build-properties است که در پیکربندی برنامه با گزینهی cleartext زیر android تنظیم میشود.
{
"plugins": [
["expo-build-properties", {
"android": { "usesCleartextTraffic": true }
}]
]
}قطعهکد فقط گزینهی افزونه را تنظیم میکند؛ مانیفست بعداً تولید میشود. یک prebuild یا یک build تازهی کلاینت توسعه اجرا کنید، سپس پیش از آزمون دوباره، فایل AndroidManifest.xml تولیدشده را از نظر android:usesCleartextTraffic بررسی کنید، چون بارگذاری دوبارهی فقط JS مانیفست قدیمی را نگه میدارد. نسخهی افزونه را با Expo SDKی که پروژه روی آن اجرا میشود هماهنگ کنید. گزینههای افزونه بین نسخهها جابهجا میشوند و قطعهکدی که از SDK دیگری کپی شده منبعی قابلاعتماد برای بیاثر بودن بیصداست.
جریان bare و گزینهی تنگتر
برای bare React Native معادل آن android:usesCleartextTraffic روی عنصر application است، یا یک پیکربندی امنیت شبکه که cleartext را فقط برای دامنههای نامبرده مجاز میداند. شکل محدود به دامنه همان است که باید ترجیح داد، چون API داخلی را مجاز میکند و همهچیز دیگر را روی HTTPS میگذارد. همچنین فهرست استثناهای خودش را مستند میکند، و این همان بخشی است که بازبین دربارهاش میپرسد.
هیچکدام از دو رویکرد پیشفرض پلتفرم را برای چیزی که نام نبردهاید تغییر نمیدهد.
اول آن را از گزارش دستگاه اثبات کنید
پیش از ویرایش پیکربندی، شکست دقیق را به دست آورید. adb logcat روی یک دستگاه متصل، رد cleartext توسط پلتفرم را نشان میدهد و مؤلفهای را که آن را برانگیخته نام میبرد. سوکت ردشده، نامی که به نشانی تبدیل نمیشود یا دستدادن TLS ناموفق به جای کاملاً دیگری اشاره میکنند، و فعال کردن cleartext فقط برنامه را بیدلیل ضعیف میکند.
سپس تولید را صادق نگه دارید. cleartext برای یک نقطهی پایانی آزمایشگاهی که نمیتواند TLS ارائه کند پذیرفتنی است، و فقط برای کوتاهترین زمانی که میتوانید برنامهریزی کنید. اگر API بتواند TLS را درون شبکهی خصوصی پایان دهد، گواهی را در مخزن اعتماد دستگاه بگذارید و cleartext را غیرفعال بگذارید، چون تونل مسیر تا خروجیاش را رمزگذاری میکند و نه چیزی پس از آن.
بهمحض اینکه نقطهی پایانی روی HTTPS پاسخ داد، مجوز را بردارید، دوباره build کنید و در همان نشست روی VPN و روی Wi-Fi معمولی آزمون کنید. تبدیل نامها به نشانی میتواند بین این دو مسیر متفاوت باشد، و تنها مقایسهی این دو نشان میدهد کدامیک راست میگوید.