Как обезопасить Android приложение
Russian (Pусский) translation by Ellen Nelson (you can also view the original English article)
Вступление
В операционной системе Android имеется множество встроенных функций безопасности, таких как изолированная программная среда приложения, защита от атак переполнения буфера, а также отдельных сегментов памяти для программных инструкций и данных. В результате простые приложения Android, которые не задействуют файловую систему или сетевые операции, часто могут считаться безопасными по умолчанию.
Тем не менее, если вы разрабатываете более сложное приложение, вы несете ответственность за его защиту и защиту конфиденциальности ваших пользователей. В этой статье я расскажу о некоторых из лучших способов, которые вы можете использовать, чтобы создать безопасное приложение для Android, которое не будет терять данные или разрешения, и в целом менее уязвимо для вредоносных приложений, которые могут быть установлены на Пользовательское устройство.
1. Используйте внутреннее хранилище для важных данных
Каждое приложение Android имеет связанный с ним внутренний каталог хранилища, путь к которому основан на названии пакета приложения. Файлы внутри этого каталога очень безопасны, потому что по умолчанию они используют режим создания файла MODE_PRIVATE
. Это означает, что доступ к файлам для любого другого приложения на устройстве невозможен. Таким образом, это лучшее место для хранения всех конфиденциальных данных вашего приложения во внутреннем хранилище.
Чтобы определить абсолютный путь к каталогу внутреннего хранилища вашего приложения, рекомендуется использовать метод getFilesDir()
. Когда вы знаете свой путь, ссылаться на файлы внутри него так же просто, как ссылаться на файлы внутри любого другого каталога. Например, вот как вы могли бы ссылаться на файл myfile.dat во внутреннем хранилище вашего приложения:
1 |
File myFile = new File(getFilesDir(), "myfile.dat"); |
2. Шифруйте данные на внешнем хранилище
Внутренняя вместимость хранилища Android часто ограничена. Поэтому время от времени у вас может не оказаться выбора, кроме как хранить конфиденциальные данные на внешних носителях, таких как съемная SD-карта.
Поскольку данные на внешних носителях могут быть доступны как пользователям, так и другим приложениям на устройстве, важно хранить их в зашифрованном виде. Одним из самых популярных алгоритмов шифрования, используемых сегодня разработчиками, является AES, сокращение от Advanced Encryption Standard, с размером ключа 256 бит.
Написание кода для шифрования и дешифрования данных вашего приложения с помощью пакета javax.crypto
, который входит в Android SDK, может ввести в заблуждение. Поэтому большинство разработчиков предпочитают использовать сторонние библиотеки, такие как библиотека Facebook's Conceal, с которой обычно проще работать.
3. Используйте Intents для IPC
Опытные программисты, которые плохо знакомы с разработкой приложений для Android, часто пытаются использовать сокеты, именные каналы или общие файлы для асинхронного взаимодействия с другими приложениями, установленными на устройстве Android. Такие подходы не только тяжёлые и не элегантные, но и подвержены угрозам. Более простой и безопасный подход к межпроцессному взаимодействию в операционной системе Android заключается в использовании интентов.
Чтобы отправить данные определенному компоненту приложения, необходимо создать новый экземпляр класса Intent
и использовать его метод setComponent()
для указания названия пакета приложения и названия компонента. Затем вы можете добавить к нему данные с помощью метода putExtra()
.
Например, вот как можно отправить строку Hello World в Activity
, названную MyActivity, которая принадлежит приложению с названием пакета my.other.app:
1 |
// Create an intent
|
2 |
Intent intent = new Intent(); |
3 |
|
4 |
// Specify the component name
|
5 |
intent.setComponent( |
6 |
new ComponentName("my.other.app","my.other.app.MyActivity") |
7 |
);
|
8 |
|
9 |
// Add data
|
10 |
intent.putExtra("DATA", "Hello World!"); |
11 |
|
12 |
// Send the intent to the activity
|
13 |
startActivity(intent); |
Чтобы отправить данные сразу в несколько приложений, вы можете отправить интент в виде трансляции с помощью метода sendBroadcast()
. Однако по умолчанию такая передача может быть прочитана любым приложением, которое имеет настроенный BroadcastReceiver
.
Поэтому, если вы хотите отправить конфиденциальную информацию методом трансляции, вы должны использовать специальное разрешение, protectionLevel
которого настроен на signature
. Таким образом, операционная система Android гарантирует, что только приложения, подписанные вашим ключом, могут получать эту передачу данных.
Вот фрагмент кода, который показывает, как отправить строку Hello World в качестве безопасной трансляции:
1 |
// Create an intent
|
2 |
Intent intent = new Intent(); |
3 |
|
4 |
// Add data
|
5 |
intent.putExtra("DATA", "Hello World"); |
6 |
|
7 |
// Specify an action name for
|
8 |
// the receiver's intent-filter
|
9 |
intent.setAction("my.app.receive"); |
10 |
|
11 |
// Send as a broadcast using a custom permission
|
12 |
sendBroadcast(intent, "my.custom.permission"); |
Обратите внимание, что приведенный выше код работает так, как ожидалось, только если объявлено настраиваемое (custom) разрешение и используется в файлах манифеста как для приложений-отправителей, так и для получателей.
1 |
<permission android:name="my.custom.permission" |
2 |
android:protectionLevel="signature"/> |
3 |
<uses-permission android:name="my.custom.permission"/> |
4. Используйте HTTPS
Все коммуникации между вашим приложением и вашими серверами должны проходить через HTTPS соединение, предпочтительно с использованием класса HttpsURLConnection
. Если вы считаете, что это правильно — использовать HTTP для данных, которые не являются конфиденциальными, — подумайте еще раз.
Многие пользователи Android каждый день подключаются к нескольким открытым точкам доступа Wi-Fi в общественных местах. Некоторые из этих точек могут быть скомпрометированы. Злоумышленник может легко изменить содержимое HTTP-трафика так, что ваше приложение начнет вести себя непредсказуемым образом или, что еще хуже, встроит в него рекламу или эксплойты.
Используйте HTTPS, пока сервер настроен на сертификат, выданный доверенным центром сертификации, таким как DigiCert или GlobalSign и вы можете быть уверены в том, что сетевой трафик защищен как от подслушивания, так и от атак типа «человек-по-середине».
Если в вашем приложении много сетевого кода, и вы опасаетесь, что вы можете непреднамеренно отправить некоторые данные в виде простого текста, вам следует рассмотреть возможность использования инструмента с открытым исходным кодом — nogotofail, созданного Google, чтобы находить такие ошибки.
5. Используйте GCM вместо SMS
Раньше, когда GCM (сокращение для Google Cloud Messaging) не существовало, многие разработчики использовали SMS для передачи данных со своих серверов в свои приложения. Сегодня это практически не практикуется.
Если вы один из тех разработчиков, которые еще не перешли с SMS на GCM, вы должны знать, что протокол SMS не зашифрован и не защищен от спуфинга. Более того, SMS может быть прочитано любым приложением на устройстве пользователя, которое имеет разрешение READ_SMS
.
GCM гораздо более безопасен и является предпочтительным способом доставки сообщений в приложение, поскольку все GCM сообщения шифруются. Они аутентифицируются с использованием регулярно обновляемых токенов регистрации на стороне клиента и уникального ключа API на стороне сервера. Чтобы узнать больше о GCM, вы можете обратиться к этому руководству о push-уведомлениях.
6. Перестаньте запрашивать персональные данные.
В последнее время для пользователя важна конфиденциальность. На самом деле существуют законы, такие как Директива Европейского Союза о защите данных и Закон Канады о защите личной информации и электронных документов, которые предусматривают защиту конфиденциальности пользователя. Поэтому, если у вас нет достаточных оснований и очень надежной инфраструктуры для сбора, хранения и передачи личной информации пользователя, вы должны избегать прямого запроса таких данных в ваших приложениях.
Лучший подход к проверке подлинности пользователей и информации из профиля пользователя — это поиск по Android через платформу Google Identity Platform. Платформа Google Identity Platform позволяет пользователям быстро входить в ваше приложение, используя свою учетную запись Google. После успешного входа на платформу, если это необходимо, ваше приложение может легко просматривать различные сведения о пользователе, такие как имя пользователя, адрес электронной почты, фото профиля, контакты и т.д. Кроме того, вы можете использовать бесплатные службы, такие как Firebase, которые могут управлять аутентификацией пользователя.
Если вы сами должны обрабатывать учетные данные пользователя, рекомендуется хранить и передавать их в виде безопасных хешей. Самый простой способ создавать разные типы хешей с помощью SDK для Android — это использовать класс MessageDigest
.
Вот небольшой фрагмент кода, который показывает, как создать хеш строки Hello World с помощью хэш-функции SHA-256:
1 |
// Initialize MessageDigest to use SHA-256
|
2 |
MessageDigest md = MessageDigest.getInstance("SHA-256"); |
3 |
|
4 |
// Convert the string to a hash
|
5 |
byte[] sha256Hash = md.digest("Hello World".getBytes()); |
7. Проверяйте информацию, которую вводят пользователи
В системе Android неправильный ввод данных от пользователя обычно не приводит к проблемам безопасности, например, переполнению буфера. Однако, если вы разрешаете пользователям взаимодействовать с базой данных SQLite или поставщиком контента, который использует внутреннюю базу данных SQLite, вы должны либо тщательно обрабатывать (sanitize) ввод пользователя, либо использовать параметры в запросах. В противном случае ваши данные могут стать уязвимыми для атак по методу SQL-инъекций.
По аналогии, проверка и очистка пользовательского ввода также очень важны, если вы используете пользовательский ввод для динамического генерирования кода для работы на встроенном скриптовом движке, таком как Mozilla Rhino.
8. Используйте ProGuard перед публикацией
Меры безопасности, встроенные в приложение Android, могут быть серьезно нарушены, если злоумышленники могут получить доступ к исходному коду. Прежде чем опубликовать свое приложение, рекомендуется использовать инструмент ProGuard, который входит в Android SDK, чтобы запутать (obfuscate) и уменьшить исходный код.
Android Studio автоматически включает ProGuard в процесс сборки, если buildType
настроен на release
. Стандартная конфигурация ProGuard, доступная в файле Android SDK proguard-android.txt, достаточна для большинства приложений. Если вы хотите добавить свои правила в конфигурацию, вы можете сделать это в файле proguard-rules.pro, который является частью каждого проекта Android Studio.
Вывод
Надеюсь, теперь вы лучше понимаете, как сделать ваши приложения для Android безопасными. Большинство рекомендаций, упомянутых в этой статье, применимы только в том случае, если вы используете Android SDK для разработки своих приложений. Если вы используете Android NDK, вы должны быть намного внимательнее, потому что при программировании на языке C вам придется управлять деталями нижнего-уровня, такими как указатели и распределение памяти.
Чтобы узнать больше о безопасности на Android, вы можете обратиться к документации по безопасности AOSP.