شناسه های دستگاه

اندروید ۱۰ مجوزهای مربوط به شناسه‌های دستگاه را تغییر می‌دهد، به طوری که اکنون همه شناسه‌های دستگاه توسط مجوز READ_PRIVILEGED_PHONE_STATE محافظت می‌شوند. قبل از اندروید ۱۰، شناسه‌های پایدار دستگاه (IMEI/MEID، IMSI، سیم‌کارت و سریال ساخت) در پشت مجوز زمان اجرا READ_PHONE_STATE محافظت می‌شدند. مجوز READ_PRIVILEGED_PHONE_STATE فقط به برنامه‌های امضا شده با کلید پلتفرم و برنامه‌های سیستمی ممتاز اعطا می‌شود.

اطلاعات بیشتر در مورد الزامات جدید مجوز را می‌توانید در صفحات Javadoc برای TelephonyManager.java و Build.java بیابید.

این تغییر بر API های زیر تأثیر می‌گذارد:

  • مدیر تلفن#getDeviceId
  • مدیر تلفن#getImei
  • مدیر تلفن#getMeid
  • TelephonyManager#getSimSerialNumber
  • مدیر تلفن#getSubscriberId
  • ساخت#دریافت سریال

دسترسی به برنامه‌های اپراتور بدون نیاز به مجوز READ_PRIVILEGED_PHONE_STATE

برنامه‌های اپراتور از پیش نصب‌شده که واجد شرایط مجوز READ_PRIVILEGED_PHONE_STATE نیستند، می‌توانند یکی از گزینه‌های جدول زیر را پیاده‌سازی کنند.

گزینه توضیحات محدودیت‌ها
امتیازات حامل UICC پلتفرم اندروید، گواهی‌های ذخیره‌شده در UICC را بارگذاری می‌کند و به برنامه‌هایی که توسط این گواهی‌ها امضا شده‌اند، اجازه می‌دهد تا با متدهای خاص تماس برقرار کنند. اپراتورهای قدیمی، جمعیت بزرگی از سیم‌کارت‌ها را در اختیار دارند که به‌روزرسانی آن‌ها به راحتی امکان‌پذیر نیست. همچنین، اپراتورهایی که حق مجوز برای سیم‌کارت‌های جدید را ندارند (به عنوان مثال، اپراتورهای مجازی موبایل (MVNO) که سیم‌کارت‌هایشان از اپراتورهای موبایل صادر شده است) نمی‌توانند گواهی‌نامه‌هایی را به سیم‌کارت‌ها اضافه یا به‌روزرسانی کنند.
لیست مجاز OEM تولیدکنندگان اصلی تجهیزات (OEM) می‌توانند از OP_READ_DEVICE_IDENTIFIER برای ارائه شناسه‌های دستگاه جهت مجاز کردن برنامه‌های اپراتور فهرست‌شده استفاده کنند. این راهکار برای همه اپراتورها قابل اجرا نیست.
کد تخصیص نوع (TAC) از متد getTypeAllocationCode که در اندروید ۱۰ معرفی شده است، برای نمایش TAC که اطلاعات سازنده و مدل را برمی‌گرداند، استفاده کنید. اطلاعات موجود در TAC برای شناسایی یک دستگاه خاص کافی نیست.
MSISDN اپراتورها می‌توانند از شماره تلفن (MSISDN) که در TelephonyManager با گروه مجوز PHONE موجود است، برای جستجوی IMEI در سیستم‌های پشتیبان خود استفاده کنند. این امر مستلزم سرمایه‌گذاری قابل توجهی برای اپراتورها است. اپراتورهایی که کلیدهای شبکه خود را با استفاده از IMSI نگاشت می‌کنند، برای تغییر به MSISDN به منابع فنی قابل توجهی نیاز دارند.

همه برنامه‌های اپراتور می‌توانند با به‌روزرسانی فایل CarrierConfig.xml با هش گواهی امضای برنامه اپراتور، به شناسه‌های دستگاه دسترسی پیدا کنند. هنگامی که برنامه اپراتور روشی را برای خواندن اطلاعات ممتاز فراخوانی می‌کند، پلتفرم به دنبال هش گواهی امضای برنامه (امضای SHA-1 یا SHA-256 گواهی) در فایل CarrierConfig.xml می‌گردد. اگر تطابقی پیدا شود، اطلاعات درخواستی بازگردانده می‌شود. اگر تطابقی پیدا نشود، یک استثنای امنیتی بازگردانده می‌شود.

برای پیاده‌سازی این راهکار، اپراتورهای تلفن همراه باید مراحل زیر را دنبال کنند:

  1. CarrierConfig.xml با هش گواهی امضای برنامه‌ی حامل به‌روزرسانی کنید و یک وصله (patch) ارسال کنید .
  2. از تولیدکنندگان اصلی تجهیزات (OEM) بخواهید که ساخت خود را با QPR1+ (توصیه می‌شود) یا این وصله‌های پلتفرم مورد نیاز و وصله‌ای که حاوی فایل CarrierConfig.xml به‌روزرسانی‌شده از مرحله ۱ بالا است، به‌روزرسانی کنند.

پیاده‌سازی

فهرست مجوزهای ممتاز خود را به‌روزرسانی کنید تا مجوز READ_PRIVILEGED_PHONE_STATE را به آن دسته از برنامه‌های ممتازی که نیاز به دسترسی به شناسه‌های دستگاه دارند، اعطا کنید.

برای کسب اطلاعات بیشتر در مورد allowlisting، به Privileged Permission Allowlisting مراجعه کنید.

برای فراخوانی APIهای آسیب‌دیده، یک برنامه باید یکی از الزامات زیر را داشته باشد:

  • اگر برنامه یک برنامه با دسترسی ممتاز از پیش بارگذاری شده باشد، به مجوز READ_PRIVILEGED_PHONE_STATE که در AndroidManifest.xml اعلام شده است، نیاز دارد. برنامه همچنین باید این دسترسی ممتاز را در لیست مجوزها قرار دهد.
  • برنامه‌هایی که از طریق گوگل پلی ارائه می‌شوند، به امتیازات اپراتور نیاز دارند. برای کسب اطلاعات بیشتر در مورد اعطای امتیازات اپراتور، به صفحه امتیازات اپراتور UICC مراجعه کنید.
  • یک برنامه مالک دستگاه یا نمایه که مجوز READ_PHONE_STATE به آن اعطا شده است.

برنامه‌ای که هیچ یک از این الزامات را برآورده نکند، رفتار زیر را خواهد داشت:

  • اگر برنامه pre-Q را هدف قرار داده و مجوز READ_PHONE_STATE به آن اعطا نشده باشد، SecurityException فعال می‌شود. این رفتار فعلی pre-Q است زیرا این مجوز برای فراخوانی این APIها لازم است.
  • اگر برنامه pre-Q را هدف قرار داده و مجوز READ_PHONE_STATE را دریافت کرده باشد، برای تمام APIهای TelephonyManager مقدار null و برای متد Build#getSerial Build.UNKNOWN دریافت می‌کند.
  • اگر برنامه برای اندروید ۱۰ یا بالاتر طراحی شده باشد و هیچ یک از الزامات جدید را برآورده نکند، یک خطای SecurityException دریافت می‌کند.

اعتبارسنجی و آزمایش

مجموعه تست سازگاری (CTS) شامل تست‌هایی برای تأیید رفتار دسترسی مورد انتظار به شناسه دستگاه برای برنامه‌های دارای امتیاز اپراتور، صاحبان دستگاه و پروفایل و برنامه‌هایی است که انتظار می‌رود به شناسه‌های دستگاه دسترسی نداشته باشند.

آزمایش‌های CTS زیر مختص این ویژگی هستند.

cts-tradefed run cts -m CtsCarrierApiTestCases -t
    android.carrierapi.cts.CarrierApiTest

cts-tradefed run cts -m CtsTelephonyTestCases -t
    android.telephony.cts.TelephonyManagerTest

cts-tradefed run cts -m CtsTelephony3TestCases

cts-tradefed run cts -m CtsPermissionTestCases -t
    android.permission.cts.TelephonyManagerPermissionTest

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCanGetDeviceIdentifiers

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCanGetDeviceIdentifiers

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCannotGetDeviceIdentifiersWithoutPermission

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCannotGetDeviceIdentifiersWithoutPermission

سوالات متداول

برای یک (MCC، MNC) مشخص، چند برنامه را می‌توان در CarrierConfig.xml مجاز کرد؟

هیچ محدودیتی برای تعداد هش‌های گواهی موجود در آرایه وجود ندارد.

برای اینکه یک برنامه در لیست مجاز قرار بگیرد، باید از کدام پارامترهای CarrierConfig در CarrierConfig.xml استفاده کنم؟

از آیتم پیکربندی سطح بالای زیر در فایل CarrierConfig.xml مخصوص گزینه‌های AOSP که پیکربندی می‌کنید، استفاده کنید:

<string-array name="carrier_certificate_string_array" num="2">
    <item value="BF02262E5EF59FDD53E57059082F1A7914F284B"/>
    <item value="9F3868A3E1DD19A5311D511A60CF94D975A344B"/>
</string-array>

آیا یک الگوی پایه CarrierConfig وجود دارد که بتوانم از آن استفاده کنم؟

از الگوی زیر استفاده کنید. این الگو باید به دارایی مربوطه اضافه شود.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<carrier_config>
    <string-array name="carrier_certificate_string_array"
num="1">
        <item value="CERTIFICATE_HASH_HERE"/>
    </string-array>
</carrier_config>

آیا برای دسترسی به شناسه‌های دستگاه، سیم‌کارت اپراتور باید در دستگاه باشد؟

CarrierConfig.xml مورد استفاده بر اساس سیم‌کارتی که در حال حاضر وارد شده است تعیین می‌شود. این بدان معناست که اگر برنامه اپراتور X سعی کند در حالی که سیم‌کارت اپراتور Y وارد شده است، به امتیازات دسترسی دسترسی پیدا کند، دستگاه نمی‌تواند هش را پیدا کند و یک استثنای امنیتی برمی‌گرداند.

در دستگاه‌های چند سیم‌کارته، اپراتور شماره ۱ فقط به سیم‌کارت شماره ۱ دسترسی دارد و برعکس.

چگونه اپراتورهای تلفن همراه گواهی امضای یک برنامه را به هش تبدیل می‌کنند؟

برای تبدیل گواهی‌های امضا به هش قبل از اضافه کردن آنها به CarrierConfig.xml ، موارد زیر را انجام دهید:

  1. امضای گواهی امضا را با استفاده از toByteArray به آرایه‌ای از بایت‌ها تبدیل کنید.
  2. از MessageDigest برای تبدیل آرایه بایت به یک هش از نوع byte[] استفاده کنید.
  3. هش را از byte[] به فرمت رشته هگز تبدیل کنید. برای مثال، به IccUtils.java مراجعه کنید.

    List<String> certHashes = new ArrayList<>();
    PackageInfo pInfo; // Carrier app PackageInfo
    MessageDigest md =
    MessageDigest.getInstance("SHA-256");
    for (Signature signature : pInfo.signatures) {
        certHashes.add(bytesToHexString(md.digest(signature.toByteArray()));
    }
  4. اگر certHashes آرایه‌ای با اندازه 2 و مقادیر 12345 و 54321 است، موارد زیر را به فایل پیکربندی حامل اضافه کنید.

    <string-array name="carrier_certificate_string_array" num="2">
        <item value="12345"/>
        <item value="54321"/>
    </string-array>