Контент-провайдери - слабке місце в Android-додатках
Зміст статті
В середньому на Android-пристроях доступно більше ста контент-провайдерів, що експортуються. Вони постачаються як системними програмами, так і тими програмами, які користувачі встановлюють самостійно. Уразливість у контент-провайдерах автоматично ставить власника пристрою під удар. Більше того, хто завгодно може звертатися до відкритих контент-провайдерів, не маючи привілеїв, що спеціально запитуються. І додаток, який акуратно вважає твої приватні дані, фактично не виявить жодних ознак шкідливого коду.
Сам собі злісний Буратіно
На сторінках журналу вже не раз обговорювалися особливості розробки додатків для платформи Android, тому ми не зайвий раз заглиблюватимемося в вже відомі читачеві деталі. Але все-таки я трохи розповім про архітектуру Android і деякі її особливості.
Важливою можливістю всім операційних систем загального призначення завжди були різноманітні методи межпроцессного взаємодії. У відносно молодій ОС Android було використано дуже багато зручних рішень, які мали полегшити життя розробникам. Одним із таких рішень стали контент-провайдери. Контент-провайдер – це постачальник даних. Будь-яка програма може створити свого контент-провайдера, який після встановлення програми буде зареєстрований операційною системою (див. врізку «Як задаються властивості контент-провайдера»).
Розмежування доступу та контент-провайдери
Андроїд проектувався як досить захищена платформа, про контент-провайдерів розробники операційної системи подбали. Вони надали дуже гнучку систему розмежування доступу, що дозволяє на багатьох рівнях тонко відрегулювати всі можливості взаємодії.
На найвищому рівніможна просто зробити провайдер неекспортованим і користуватися ним усередині своєї програми. Якщо ми таки вирішили його експортувати, то можна глобально обмежити до нього доступ за допомогою параметра android:permission в секції маніфесту. Як дозвіл можна використовувати будь-яке, вже визначене в системі, або задати своє власне. Це дуже зручно, якщо ми хочемо дозволити доступ до провайдера групи своїх додатків. Ми просто даємо всім своїм додаткам нестандартний дозвіл, таким самим дозволом закриваємо доступ до провайдера. Після цього всі програми з нашої затишної інфраструктури матимуть доступ до провайдера на читання та запис.
Для більш тонкого регулювання можна використовувати параметри android:readPermission та android:writePermission. Як зрозуміло з їхніх назв, вони дозволяють встановити окремо обмеження доступу читання чи запис. Причому ці параметри мають більший пріоритет, ніж загальний параметр android:permission.
Але є ще один, більш глибокий рівень регулювання доступу. Він дозволяє дозволити доступ до певного набору інформації, яку постачає провайдер. На повну котушку у разі використовується те, що доступом до провайдеру здійснюється через URI bit.ly.
На жаль, не всі розробники приділяють увагу питанням безпеки, тому багато програм реєструють в операційній системі контент-провайдери повністю відкриті як на читання, так і на запис.
Проблеми та рішення
Отже, ми вже можемо зробити попередні висновки про те, чим нам загрожує погано реалізований контент-провайдер:
- Несанкціонований доступ до персональних даних користувача та чутливої інформації. Причиною може бути відкритий контент-провайдер, який встановило в системулегітимний додаток з високим рівнем привілеїв. Припустимо, ми хочемо почитати зі своєї не зовсім легальної програми SMS користувача. Якщо ми запросимо дозвіл READ_SMS, то привернемо до себе непотрібну увагу. Та й людину, яка встановить програму, яка читає SMS, ще потрібно пошукати. З іншого боку, можна пошукати вже зареєстрований у системі контент-провайдер, який встановив привілейовану сторонню або вбудовану програму.
- Вразливості типу SQL injection у провайдерах, що працюють з базами даних. На жаль, фільтрація введення користувача повністю віддана на відкуп розробнику мобільних додатків. Понад те, «корпорація добра» залишила у документації безліч грабель, куди наступають програмісти. Так, у розділі Content Prov інтерфейс командного рядка MWR Mercury
Хакер #170. Малвар для OS X
Пишемо свою утиліту для аналізу контент-провайдерів
Раніше я згадав Mercury від MWR Labs. Це чудовий набір інструментів, і я рекомендую ним користуватися. На жаль, особисто мене спантеличує один погляд на користувальницьку ліцензійну угоду, під яку потрапляє цей продукт. Крім того, найкраще засвоїти матеріал на практиці, тим більше коли програмування не становить суттєвої складності.
Напишемо свою програму під Android для аналізу контент-провайдерів. Що ми зробимо?
- Отримаємо інформацію про всіх зареєстрованих в операційній системі контент-провайдерів.
- Визначимо які з цих провайдерів не захищені за допомогою привілеїв.
- Трохи поекспериментуємо;).
Як я вже згадував, провайдери реєструються в операційній системі під час встановлення програми. Тому найзручнішим інструментомДля отримання інформації буде PackageManager.
Об'єкт типу ProviderInfo містить усю необхідну нам інформацію. Ми отримаємо відповідний ContentResolver та обробимо результат та можливі винятки.
Решта коду нашої програми служить для оформлення інтерфейсу користувача, тому я її опускаю. На виході ми здобули невелику утиліту.




З цікавістю дізнаємося, що ми отримали доступ до бази даних з табличкою facefeature наступного виду:
Дані з цієї таблиці легко читаються, до речі, зауважу, що наша тестова утиліта не вимагає жодних привілеїв. Але при цьому цілком можна вважати особливості твого обличчя :).
Цікавий результат дає звернення до "content://com.google.settings/sqlite_master-" (що ж, і Google промахується):
Подальші експерименти залишаю читачеві. Всі вихідні тексти утиліти доступні на GitHub.
Як задаються властивості контент-провайдера
Якщо звернутися до Android SDK (де весь процес розписаний дуже докладно і по кроках), то видно, що для того, щоб зареєструвати свій контент-провайдер, тобі доведеться додати опис провайдера файл AndroidManifest.xml в секцію. Параметрів при цьому можна вказати безліч bit.ly, але ми розглянемо лише важливі для нас:
Важлива особливість — доступ до даних здійснюватиметься за допомогою спеціального URI зі схемою «content». Параметр android:authorities є унікальним ідентифікаторомпровайдера і є першою частиною URI, друга частина буде вказувати на те, які саме дані ми хочемо отримати. Параметр android:exported показує, чи доступний провайдер для інших програм. Вже тут є невелика особливість, яка може зіпсувати життя розробнику. Цей параметр у версіях Android до 16-ї включно (Android 4.1 JELLY_BEAN) за умовчанням встановлений у «true», і всі контент-провайдери експортуються, звичайно, така ситуація не є безпечною. Але тільки з версії 17 (Android 4.2 JELLY_BEAN_MR1) в ОС було внесено виправлення, і тепер, щоб експортувати провайдер, необхідно самостійно змінити «false», що використовується за умовчанням.
Отже, у нашому випадку для доступу до контент-провайдера можна буде використовувати URI:
Фантазія розробника при написанні провайдера мало чим обмежена, справа в тому, що обов'язково потрібно перевизначити лише шість абстрактних методів (query(), insert(), update(), delete(), getType(), onCreate()). При цьому ніхто не забороняє зробити ці методи порожніми, повертати будь-який запит константу, результат читання файлу або звернення до мережі. Тим більше, якщо твій провайдер надає доступ до даних тільки на читання, то методи insert(), update() і так далі йому зовсім не потрібні.

І хоча ніхто не примушує програміста ховати «під капотом» свого контент-провайдера базу даних, але часто тут зустрічається добре знайома всім розробникам мобільних додатків для Android SQLite. Тим більше, що ContentResolver, що використовується для отримання даних, завжди повертає об'єкт типу Cursor, що тонко натякає…
MEMENTO MORI
Отже, ми розглянули одне із слабких місць в Android-додатках. Я постарався показати, наскільки важливо використовувати помаксимуму можливості розмежування доступу, які пропонує операційна система.
Розробникам мобільних програм хочеться нагадати, що, написавши контент-провайдер, ви приймаєте рішення поділитися інформацією, тому варто подумати, хто і в якому обсязі зможе отримати до неї доступ. Також багато хто забуває, що вразливості типу SQL injection схильні не тільки до веб-додатків. Тому санітизацію введення користувача і використання prepared statements ніхто не скасовував, навіть під Android.