В Android встроены функции безопасности, которые значительно снижают частоту и последствия проблем с безопасностью приложений. Система разработана таким образом, что вы, как правило, можете создавать свои приложения с правами доступа к системе и файлам по умолчанию, избегая сложных решений в области безопасности.
Следующие основные функции безопасности помогут вам создавать защищенные приложения:
- Песочница для Android-приложений, которая изолирует выполнение данных и кода вашего приложения от других приложений.
- Платформа для разработки приложений с надежной реализацией распространенных функций безопасности, таких как криптография, управление правами доступа и защищенное межпроцессное взаимодействие (IPC).
- Для снижения рисков, связанных с распространенными ошибками управления памятью, используются такие технологии, как рандомизация расположения адресного пространства (ASLR) , no-execute (NX) , ProPolice, safe_iop , OpenBSD
dlmallocиcalloc, а также Linuxmmap_min_addr. - Пользователь предоставляет разрешения на ограничение доступа к функциям системы и пользовательским данным.
- Настраиваемые для каждого приложения разрешения позволяют управлять данными приложения на индивидуальной основе.
Важно ознакомиться с рекомендациями по обеспечению безопасности Android, представленными на этой странице. Следование этим рекомендациям в качестве общих принципов программирования поможет вам избежать непреднамеренного возникновения проблем с безопасностью, которые негативно скажутся на ваших пользователях.
Аутентификация
Аутентификация является необходимым условием для многих ключевых операций обеспечения безопасности. Для контроля доступа к защищенным ресурсам, таким как пользовательские данные, функциональность приложения и другие ресурсы, вам потребуется добавить аутентификацию в ваше Android-приложение.
Вы можете улучшить процесс аутентификации пользователей, интегрировав ваше приложение с Credential Manager . Credential Manager — это библиотека Android Jetpack, которая объединяет поддержку API для большинства основных методов аутентификации, включая ключи доступа, пароли и решения для федеративной авторизации, такие как Sign-in with Google .
Для дальнейшего повышения безопасности вашего приложения рассмотрите возможность добавления методов биометрической аутентификации, таких как сканирование отпечатков пальцев или распознавание лиц. Подходящими кандидатами для добавления биометрической аутентификации могут быть приложения для финансовых, медицинских учреждений или систем управления идентификацией.
Функция автозаполнения в Android упрощает процесс регистрации и входа в систему, снижая количество ошибок и неудобства для пользователей. Автозаполнение интегрируется с менеджерами паролей, позволяя пользователям выбирать сложные, случайные пароли, которые можно легко и безопасно хранить и восстанавливать.
целостность приложения
API Play Integrity помогает проверить, что взаимодействия и запросы к серверу поступают от подлинного исполняемого файла вашего приложения, работающего на подлинном устройстве под управлением Android. Выявляя потенциально опасные и мошеннические взаимодействия, например, от поддельных версий приложения и ненадежных сред, серверная часть вашего приложения может реагировать соответствующими действиями для предотвращения атак и снижения уровня злоупотреблений.
хранение данных
Наиболее распространенная проблема безопасности приложений на Android — это доступность данных, сохраненных на устройстве, для других приложений. Существует три основных способа сохранения данных на устройстве:
- Внутреннее хранилище
- Внешнее хранилище
- Поставщики контента
В следующих разделах описаны проблемы безопасности, связанные с каждым подходом.
Внутреннее хранилище
По умолчанию файлы, созданные вами во внутренней памяти, доступны только вашему приложению. Android реализует эту защиту, и для большинства приложений этого достаточно.
Избегайте устаревших режимов MODE_WORLD_WRITEABLE и MODE_WORLD_READABLE для файлов IPC. Они не позволяют ограничивать доступ к данным для конкретных приложений и не обеспечивают никакого контроля над форматом данных. Если вы хотите обмениваться данными с другими процессами приложений, рассмотрите возможность использования поставщика контента , который предоставляет другим приложениям права на чтение и запись и может динамически предоставлять разрешения в каждом конкретном случае.
Внешнее хранилище
Файлы, созданные на внешних носителях , таких как SD-карты, доступны для чтения и записи по всему миру. Поскольку внешний носитель может быть извлечен пользователем и изменен любым приложением, храните на нем только неконфиденциальную информацию.
При обработке данных с внешнего хранилища выполняйте проверку входных данных так же, как и при работе с данными из любого ненадежного источника. Не храните исполняемые файлы или файлы классов на внешнем хранилище до динамической загрузки. Если ваше приложение получает исполняемые файлы с внешнего хранилища, убедитесь, что файлы подписаны и криптографически проверены до динамической загрузки.
Поставщики контента
Поставщики контента предлагают механизм структурированного хранения, который может быть ограничен вашим собственным приложением или экспортирован для предоставления доступа другим приложениям. Если вы не планируете предоставлять другим приложениям доступ к вашему ContentProvider , отметьте его как android:exported=false в манифесте приложения. В противном случае установите атрибут android:exported в true , чтобы разрешить другим приложениям доступ к хранимым данным.
При создании ContentProvider , экспортируемого для использования другими приложениями, вы можете указать одно разрешение на чтение и запись, или же указать разные разрешения для чтения и записи. Ограничьте свои разрешения только теми, которые необходимы для выполнения поставленной задачи. Помните, что обычно проще добавить разрешения позже, чтобы предоставить доступ к новой функциональности, чем удалить их и повлиять на существующих пользователей.
Если вы используете поставщика контента для обмена данными только между своими приложениями, мы рекомендуем установить атрибут android:protectionLevel в значение «защита signature . Разрешения на основе подписи не требуют подтверждения пользователя, поэтому они обеспечивают более удобный пользовательский интерфейс и более контролируемый доступ к данным поставщика контента, когда приложения, обращающиеся к данным, подписаны одним и тем же ключом.
Поставщики контента также могут предоставлять более детальный доступ, объявляя атрибут android:grantUriPermissions и используя флаги FLAG_GRANT_READ_URI_PERMISSION и FLAG_GRANT_WRITE_URI_PERMISSION в объекте Intent , который активирует компонент. Область действия этих разрешений может быть дополнительно ограничена элементом <grant-uri-permission> .
При обращении к поставщику контента используйте параметризованные методы запросов, такие как query , update и delete() чтобы избежать потенциальных SQL-инъекций из ненадежных источников. Обратите внимание, что использование параметризованных методов недостаточно, если аргумент selection формируется путем конкатенации пользовательских данных перед отправкой их методу.
Не стоит питать ложных надежд относительно прав на запись. Права на запись позволяют использовать SQL-запросы, которые дают возможность подтвердить некоторые данные с помощью нестандартных условий WHERE и анализа результатов. Например, злоумышленник может проверить наличие определенного номера телефона в журнале звонков, изменяя строку только в том случае, если этот номер телефона уже существует. Если данные поставщика контента имеют предсказуемую структуру, права на запись могут быть эквивалентны правам на чтение и запись.
Разрешения
Поскольку Android изолирует приложения друг от друга, приложения должны явно совместно использовать ресурсы и данные. Они делают это, объявляя необходимые им разрешения для дополнительных возможностей, не предоставляемых базовой песочницей, включая доступ к функциям устройства, таким как камера.
Запросы на разрешение
Сведите к минимуму количество разрешений, запрашиваемых вашим приложением. Ограничение доступа к конфиденциальным разрешениям снижает риск непреднамеренного злоупотребления ими, повышает вовлеченность пользователей и делает ваше приложение менее уязвимым для злоумышленников. Как правило, если разрешение не требуется для функционирования вашего приложения, не запрашивайте его. См. руководство по оценке необходимости объявления разрешений вашим приложением .
По возможности, разработайте приложение таким образом, чтобы оно не требовало никаких разрешений. Например, вместо запроса доступа к информации об устройстве для создания уникального идентификатора, создайте UUID для вашего приложения. (Подробнее см. в разделе о пользовательских данных ). Или, вместо использования внешнего хранилища (для которого требуется разрешение), храните данные во внутреннем хранилище.
Помимо запроса разрешений, ваше приложение может использовать элемент <permission> для защиты межпроцессного взаимодействия (IPC), которое является критически важным с точки зрения безопасности и доступно другим приложениям, например, ContentProvider . В целом, мы рекомендуем по возможности использовать средства контроля доступа, отличные от подтвержденных пользователем разрешений, поскольку разрешения могут вызывать путаницу у пользователей. Например, рассмотрите возможность использования уровня защиты подписью для разрешений на межпроцессное взаимодействие между приложениями, предоставляемых одним разработчиком.
Не допускайте утечки данных, защищенных правами доступа. Это происходит, когда ваше приложение предоставляет данные через межпроцессное взаимодействие (IPC), которые доступны только потому, что у вашего приложения есть разрешение на доступ к этим данным. Клиенты интерфейса IPC вашего приложения могут не иметь таких же прав доступа к данным. Более подробная информация о частоте и потенциальных последствиях этой проблемы содержится в исследовательской работе «Перераспределение разрешений: атаки и защита» , опубликованной на конференции USENIX.
Определения разрешений
Определите минимальный набор разрешений, удовлетворяющих вашим требованиям безопасности. Создание нового разрешения относительно редко встречается в большинстве приложений, поскольку системные разрешения охватывают множество ситуаций. При необходимости выполняйте проверки доступа, используя существующие разрешения.
Если вам требуется новое разрешение, подумайте, сможете ли вы выполнить свою задачу с помощью уровня защиты подписью . Разрешения, основанные на подписи, прозрачны для пользователя и позволяют получить доступ только приложениям, подписанным тем же разработчиком, что и приложение, выполняющее проверку разрешения.
Если создание нового разрешения по-прежнему необходимо, объявите его в манифесте приложения, используя элемент <permission> . Приложения, использующие новое разрешение, могут ссылаться на него, добавив элемент <uses-permission> в свои файлы манифеста. Вы также можете добавлять разрешения динамически, используя метод addPermission() .
Если вы создаете разрешение с уровнем защиты «Опасный», необходимо учитывать ряд сложностей:
- Разрешение должно содержать строку, которая кратко и понятно объясняет пользователю, какое решение в области безопасности ему необходимо принять.
- Строка разрешений должна быть локализована для множества различных языков.
- Пользователи могут отказаться от установки приложения, потому что какое-либо разрешение кажется им непонятным или воспринимается как рискованное.
- Приложения могут запрашивать разрешение, даже если создатель разрешения не установлен.
Каждый из этих вариантов представляет собой серьезную нетехническую проблему для вас как разработчика, а также вводит в заблуждение ваших пользователей, поэтому мы не рекомендуем использовать опасный уровень доступа.
Сетевые технологии
Сетевые транзакции по своей природе рискованны с точки зрения безопасности, поскольку они включают передачу данных, потенциально являющихся личными для пользователя. Люди все больше осознают проблемы конфиденциальности мобильных устройств, особенно когда устройство совершает сетевые транзакции, поэтому очень важно, чтобы ваше приложение внедряло все передовые методы для обеспечения постоянной безопасности данных пользователя.
IP-сети
Работа с сетью на Android не сильно отличается от других сред Linux. Ключевым моментом является использование соответствующих протоколов для конфиденциальных данных, например, HttpsURLConnection для безопасного веб-трафика. Используйте HTTPS вместо HTTP везде, где на сервере поддерживается HTTPS, поскольку мобильные устройства часто подключаются к незащищенным сетям, таким как общедоступные точки доступа Wi-Fi.
Аутентифицированная, зашифрованная связь на уровне сокетов может быть легко реализована с помощью класса SSLSocket . Учитывая частоту подключения устройств Android к незащищенным беспроводным сетям через Wi-Fi, настоятельно рекомендуется использовать защищенные сети для всех приложений, взаимодействующих по сети.
Некоторые приложения используют сетевые порты localhost для обработки конфиденциальных межпроцессных взаимодействий (IPC). Не используйте этот подход, поскольку эти интерфейсы доступны другим приложениям на устройстве. Вместо этого используйте механизм IPC Android, где возможна аутентификация, например, с помощью Service . Привязка к неспецифическому IP-адресу INADDR_ANY хуже, чем использование обратной связи (loopback), поскольку это позволяет вашему приложению получать запросы с любого IP-адреса.
Убедитесь, что вы не доверяете данным, загруженным по протоколу HTTP или другим небезопасным протоколам. Это включает проверку входных данных в WebView и любые ответы на намерения, отправленные по протоколу HTTP.
Телефонные сети
Протокол SMS (Short Message Service) был разработан в первую очередь для обмена данными между пользователями и плохо подходит для приложений, которым необходимо передавать данные. Из-за ограничений SMS мы рекомендуем использовать Firebase Cloud Messaging (FCM) и IP-сети для отправки сообщений с данными с веб-сервера в ваше приложение на устройстве пользователя.
Учтите, что SMS-сообщения не шифруются и не проходят строгую аутентификацию ни в сети, ни на устройстве. В частности, любой получатель SMS-сообщения должен ожидать, что злоумышленник мог отправить SMS вашему приложению. Не полагайтесь на неаутентифицированные SMS-данные для выполнения конфиденциальных команд. Также имейте в виду, что SMS-сообщения могут быть подвержены подделке и/или перехвату в сети. На самом устройстве под управлением Android SMS-сообщения передаются как широковещательные интенты, поэтому их могут прочитать или перехватить другие приложения, имеющие разрешение READ_SMS .
Проверка входных данных
Недостаточная проверка входных данных — одна из наиболее распространенных проблем безопасности, затрагивающих приложения, независимо от платформы, на которой они работают. Android имеет меры противодействия на уровне платформы, которые снижают уязвимость приложений к проблемам проверки входных данных, и мы рекомендуем использовать эти функции везде, где это возможно. Кроме того, мы рекомендуем использовать типобезопасные языки программирования, чтобы снизить вероятность возникновения проблем с проверкой входных данных.
При использовании нативного кода любые данные, считанные из файлов, полученные по сети или от межпроцессного взаимодействия (IPC), потенциально могут представлять угрозу безопасности. Наиболее распространенные проблемы — переполнение буфера , использование после освобождения памяти и ошибки смещения на единицу . Android предоставляет ряд технологий, таких как ASLR и предотвращение выполнения данных (DEP), которые снижают вероятность эксплуатации этих ошибок, но не решают основную проблему. Вы можете предотвратить эти уязвимости, тщательно обрабатывая указатели и управляя буферами.
Динамические языки программирования, основанные на строках, такие как JavaScript и SQL, также подвержены проблемам проверки входных данных из-за экранирующих символов и внедрения скриптов .
Если вы используете данные в запросах, отправляемых в базу данных SQL или поставщик контента, SQL-инъекции могут стать проблемой. Лучшая защита — использование параметризованных запросов, как обсуждалось в разделе о поставщиках контента . Ограничение прав доступа только на чтение или только на запись также может снизить потенциальный вред, связанный с SQL-инъекциями.
Если вы не можете использовать функции безопасности, описанные в этом разделе, убедитесь, что используете хорошо структурированные форматы данных и проверили соответствие данных ожидаемому формату. Хотя блокировка определенных символов или замена символов могут быть эффективной стратегией, на практике эти методы чреваты ошибками, и мы рекомендуем избегать их по возможности.
Данные пользователя
Наилучший подход к обеспечению безопасности пользовательских данных — минимизировать использование API, которые получают доступ к конфиденциальной или личной информации. Если у вас есть доступ к пользовательским данным, по возможности избегайте их хранения или передачи. Рассмотрите возможность реализации логики вашего приложения с использованием хеша или необратимой формы данных. Например, ваше приложение может использовать хеш адреса электронной почты в качестве первичного ключа, чтобы избежать передачи или хранения адреса электронной почты. Это снижает вероятность непреднамеренного раскрытия данных, а также уменьшает вероятность попыток злоумышленников использовать уязвимость вашего приложения.
Аутентифицируйте пользователя всякий раз, когда требуется доступ к личным данным, используя современные методы аутентификации, такие как пароли и менеджер учетных данных . Если вашему приложению необходим доступ к личной информации, помните, что в некоторых юрисдикциях может потребоваться предоставление политики конфиденциальности, объясняющей использование и хранение этих данных. Следуйте передовым методам обеспечения безопасности, минимизируя доступ к данным пользователей, чтобы упростить соблюдение нормативных требований.
Также следует учитывать, не может ли ваше приложение непреднамеренно раскрыть личную информацию другим сторонам, например, сторонним компонентам для рекламы или сторонним сервисам, используемым вашим приложением. Если вы не знаете, зачем компоненту или сервису требуется личная информация, не предоставляйте её. В целом, ограничение доступа вашего приложения к личной информации снижает вероятность проблем в этой области.
Если вашему приложению требуется доступ к конфиденциальным данным, оцените, нужно ли передавать их на сервер или можно выполнить операцию на стороне клиента. Рассмотрите возможность выполнения любого кода, использующего конфиденциальные данные, на стороне клиента, чтобы избежать передачи пользовательских данных. Также убедитесь, что вы случайно не раскрываете пользовательские данные другим приложениям на устройстве из-за чрезмерно разрешительного межпроцессного взаимодействия (IPC), файлов с доступом для записи всем пользователям или сетевых сокетов. Чрезмерно разрешительное IPC — это частный случай утечки данных, защищенных правами доступа, который обсуждается в разделе «Запросы на разрешения» .
Если требуется глобально уникальный идентификатор (GUID), создайте большой уникальный номер и сохраните его. Не используйте телефонные идентификаторы, такие как номер телефона или IMEI, поскольку они могут быть связаны с личной информацией. Эта тема более подробно обсуждается на странице, посвященной лучшим практикам использования уникальных идентификаторов .
Будьте осторожны при записи в журналы устройства. На Android журналы являются общим ресурсом и доступны приложению с разрешением READ_LOGS . Несмотря на то, что данные журнала телефона являются временными и удаляются при перезагрузке, некорректная запись информации о пользователе может непреднамеренно привести к утечке данных пользователя в другие приложения. Помимо отказа от записи персональных данных, ограничьте использование журналов в приложениях, предназначенных для использования в производственной среде. Для упрощения реализации используйте флаги отладки и пользовательские классы Log с легко настраиваемыми уровнями логирования.
WebView
Поскольку WebView обрабатывает веб-контент, который может включать HTML и JavaScript, неправильное использование может привести к распространенным проблемам веб-безопасности, таким как межсайтовый скриптинг (внедрение JavaScript). Android включает в себя ряд механизмов для уменьшения масштаба этих потенциальных проблем путем ограничения возможностей WebView до минимального функционала, необходимого вашему приложению.
Если ваше приложение не использует JavaScript напрямую внутри WebView , не вызывайте метод setJavaScriptEnabled . В некоторых примерах кода этот метод используется; если вы используете этот метод в рабочем приложении, удалите его, если он не требуется. По умолчанию WebView не выполняет JavaScript, поэтому межсайтовая атака (XSS) невозможна.
Используйте addJavaScriptInterface() с особой осторожностью, поскольку он позволяет JavaScript вызывать операции, обычно зарезервированные для приложений Android. Если вы его используете, предоставляйте доступ к addJavaScriptInterface() только веб-страницам, от которых поступает только достоверный ввод. Если разрешен ненадежный ввод, недоверенный JavaScript может вызывать методы Android внутри вашего приложения. В целом, мы рекомендуем предоставлять доступ к addJavaScriptInterface() только JavaScript, который содержится в APK-файле вашего приложения.
Если ваше приложение обращается к конфиденциальным данным через WebView , рассмотрите возможность использования метода clearCache() для удаления всех файлов, хранящихся локально. Вы также можете использовать заголовки на стороне сервера, такие как no-store , чтобы указать, что приложение не должно кэшировать определенный контент.
Устройства, работающие на платформах старше Android 4.4 (уровень API 19), используют версию webkit , имеющую ряд проблем с безопасностью. В качестве обходного пути, если ваше приложение работает на таких устройствах, оно должно подтверждать, что объекты WebView отображают только доверенный контент. Чтобы убедиться, что ваше приложение не подвержено потенциальным уязвимостям SSL, используйте обновляемый объект Security Provider , как описано в разделе «Обновите свой поставщик безопасности для защиты от эксплойтов SSL» . Если ваше приложение должно отображать контент из открытого интернета, рассмотрите возможность предоставления собственного средства рендеринга, чтобы поддерживать его в актуальном состоянии с помощью последних исправлений безопасности.
Запросы на учетные данные
Запросы учетных данных — это потенциальный источник атак. Вот несколько советов, которые помогут вам сделать запросы учетных данных в ваших приложениях для Android более безопасными.
Минимизируйте утечку учетных данных.
- Избегайте ненужных запросов учетных данных . Чтобы фишинговые атаки были более заметны и менее вероятны, сведите к минимуму частоту запросов учетных данных пользователя. Вместо этого используйте токен авторизации и обновляйте его. Запрашивайте только минимальное количество информации, необходимой для аутентификации и авторизации.
- Надежно храните учетные данные . Используйте Credential Manager для включения аутентификации без пароля с помощью ключей доступа или для реализации федеративного входа в систему с использованием таких схем, как «Вход через Google». Если вам необходимо использовать традиционную аутентификацию по паролю, не храните идентификаторы пользователей и пароли на устройстве. Вместо этого выполните первоначальную аутентификацию, используя имя пользователя и пароль, предоставленные пользователем, а затем используйте кратковременный, специфичный для службы токен авторизации.
- Ограничьте объем прав доступа . Не запрашивайте широкие права доступа для задачи, которая требует лишь более узких прав.
- Ограничьте использование токенов доступа . Используйте операции с кратковременными токенами и вызовы API.
- Ограничьте частоту аутентификации . Быстрые, последовательные запросы на аутентификацию или авторизацию могут быть признаком атаки методом перебора паролей. Ограничьте частоту таких запросов до разумного уровня, сохраняя при этом функциональность и удобство использования приложения.
Используйте надежную аутентификацию.
- Внедрите ключи доступа . Включите ключи доступа как более безопасную и удобную альтернативу паролям.
- Добавьте биометрию . Предложите возможность использования биометрической аутентификации, такой как распознавание отпечатков пальцев или лица, для повышения уровня безопасности.
- Используйте федеративные поставщики идентификации . Менеджер учетных данных поддерживает федеративные поставщики аутентификации, такие как «Вход через Google» .
- Шифрование обмена данными. Используйте HTTPS и аналогичные технологии, чтобы обеспечить защиту данных, передаваемых вашим приложением по сети.
Обеспечьте безопасное управление учетными записями.
- Подключайтесь к сервисам, доступным для нескольких приложений, используя
AccountManager. Используйте классAccountManagerдля вызова облачного сервиса и не храните пароли на устройстве. - После использования
AccountManagerдля полученияAccount, перед передачей учетных данных используйтеCREATOR, чтобы случайно не передать их не тому приложению. - Если учетные данные используются только созданными вами приложениями, вы можете проверить, какое именно приложение обращается к
AccountManager, используяcheckSignatures. В качестве альтернативы, если учетные данные использует только одно приложение, вы можете использоватьKeyStoreдля их хранения.
Будьте бдительны
- Поддерживайте свой код в актуальном состоянии . Обязательно обновляйте исходный код, включая сторонние библиотеки и зависимости, чтобы защититься от новейших уязвимостей.
- Отслеживайте подозрительную активность . Ищите потенциальные случаи неправомерного использования, например, случаи злоупотребления правами доступа.
- Проведите аудит своего кода . Регулярно выполняйте проверки безопасности вашей кодовой базы, чтобы выявить потенциальные проблемы с запросами учетных данных.
управление ключами API
Ключи API являются критически важным компонентом многих приложений Android, позволяя им получать доступ к внешним сервисам и выполнять основные функции, такие как подключение к картографическим сервисам, аутентификация и поиск информации о погоде. Однако раскрытие этих конфиденциальных ключей может иметь серьезные последствия, включая утечки данных, несанкционированный доступ и финансовые потери. Для предотвращения подобных сценариев разработчикам следует внедрять безопасные стратегии обработки ключей API на протяжении всего процесса разработки.
Для защиты сервисов от неправомерного использования ключи API должны быть тщательно защищены. Чтобы обеспечить безопасность соединения между приложением и сервисом, использующим ключ API, необходимо защитить доступ к API. Когда ваше приложение скомпилировано, и исходный код вашего приложения содержит ключи API, злоумышленник может декомпилировать приложение и получить доступ к этим ресурсам.
Этот раздел предназначен для двух групп разработчиков Android: тех, кто работает с командами инфраструктуры над конвейером непрерывной доставки, и тех, кто развертывает автономные приложения в Play Store. В этом разделе изложены лучшие практики обработки ключей API, чтобы ваше приложение могло безопасно взаимодействовать с сервисами.
Генерация и хранение
Разработчикам следует рассматривать хранение ключей API как важнейший компонент защиты данных и конфиденциальности пользователей, используя многоуровневый подход к обеспечению безопасности.
Надежное хранилище ключей
Для обеспечения оптимальной безопасности управления ключами используйте Android Keystore и шифруйте сохраненные ключи с помощью надежного инструмента, такого как Tink Java .
исключение контроля источников
Никогда не добавляйте API-ключи в репозиторий исходного кода. Добавление API-ключей в исходный код сопряжено с риском раскрытия ключей общедоступным репозиториям, примерам кода и случайно опубликованным файлам. Вместо этого используйте плагины Gradle, такие как secrets-gradle-plugin, для работы с API-ключами в вашем проекте.
Ключи, специфичные для конкретной среды
По возможности используйте отдельные API-ключи для сред разработки, тестирования и производства. Используйте ключи, специфичные для каждой среды, чтобы изолировать каждую из них, снижая риск утечки данных из производственной среды и позволяя отключать скомпрометированные ключи без влияния на производственную среду.
Контроль использования и доступа
Надежные методы работы с API-ключами имеют решающее значение для защиты вашего API и ваших пользователей. Вот как подготовить ваши ключи для обеспечения оптимальной безопасности:
- Создавайте уникальные ключи для каждого приложения : используйте отдельные API-ключи для каждого приложения, чтобы выявлять и изолировать случаи несанкционированного доступа.
- Внедрите ограничения по IP-адресам : по возможности ограничьте использование ключей API определенными IP-адресами или диапазонами.
- Ограничение использования ключей в мобильных приложениях : ограничьте использование ключей API определенными мобильными приложениями, включив их в комплект с ключом или используя сертификаты приложений.
- Регистрация и мониторинг подозрительной активности : Внедрите механизмы регистрации и мониторинга использования API для выявления подозрительной активности и предотвращения потенциальных злоупотреблений.
Примечание : Ваш сервис должен предоставлять функции ограничения доступа к ключам для конкретного пакета или платформы. Например, API Google Maps ограничивает доступ к ключам по имени пакета и ключу подписи.
OAuth 2.0 предоставляет основу для авторизации доступа к ресурсам. Он определяет стандарты взаимодействия клиентов и серверов и обеспечивает безопасную авторизацию. Вы можете использовать OAuth 2.0 для ограничения использования ключей API определенными клиентами и определения области доступа таким образом, чтобы каждый ключ API имел только минимальный уровень доступа, необходимый для его предполагаемого использования.
Ключевая ротация и истечение срока действия
Для снижения риска несанкционированного доступа через необнаруженные уязвимости API важно регулярно менять ключи API. Стандарт ISO 27001 определяет рамки соответствия требованиям в отношении частоты смены ключей. В большинстве случаев достаточно периода смены ключей от 90 дней до 6 месяцев. Внедрение надежной системы управления ключами может помочь оптимизировать эти процессы, повысив эффективность смены и истечения срока действия ключей.
Общие передовые методы
- Используйте SSL/HTTPS : Всегда используйте протокол HTTPS для шифрования запросов к API.
- Привязка сертификатов : Для повышения уровня безопасности можно рассмотреть возможность внедрения привязки сертификатов , чтобы проверять, какие сертификаты считаются действительными.
- Проверка и очистка пользовательского ввода : Проверка и очистка пользовательского ввода для предотвращения инъекционных атак, которые могут привести к раскрытию ключей API.
- Следуйте передовым методам обеспечения безопасности : внедрите общие передовые методы обеспечения безопасности в процесс разработки, включая методы безопасного кодирования, проверку кода и сканирование уязвимостей.
- Будьте в курсе событий : следите за последними угрозами безопасности и передовыми методами управления ключами API.
- Обновление SDK : Убедитесь, что ваши SDK и библиотеки обновлены до последней версии.
Криптография
Помимо обеспечения изоляции данных, поддержки полного шифрования файловой системы и предоставления защищенных каналов связи, Android предлагает широкий спектр алгоритмов для защиты данных с помощью криптографии.
Узнайте, какие поставщики безопасности Java Cryptography Architecture (JCA) использует ваше программное обеспечение. Постарайтесь использовать самый высокий уровень реализации существующего фреймворка, который может поддерживать ваш сценарий использования. Если применимо, используйте поставщики, предоставленные Google, в порядке, указанном Google.
Если вам необходимо безопасно получить файл из известного сетевого расположения, достаточно будет простого URI HTTPS, не требующего знаний в области криптографии. Если вам нужен защищенный туннель, рассмотрите возможность использования HttpsURLConnection или SSLSocket вместо написания собственного протокола. При использовании SSLSocket имейте в виду, что он не выполняет проверку имени хоста. См. Предупреждения об использовании SSLSocket напрямую .
Если вам потребуется реализовать собственный протокол, не используйте собственные криптографические алгоритмы. Примените существующие криптографические алгоритмы, такие как реализации AES и RSA, представленные в классе Cipher . Кроме того, следуйте этим рекомендациям:
- Для коммерческих целей используйте 256-битное AES. (Если оно недоступно, используйте 128-битное AES.)
- Для криптографии на эллиптических кривых (ЭК) используйте открытые ключи размером 224 или 256 бит.
- Знайте, когда использовать блочные режимы CBC, CTR или GCM.
- Избегайте повторного использования IV/счетчика в режиме CTR. Убедитесь, что они криптографически случайны.
- При использовании шифрования целостность данных следует обеспечивать в режиме CBC или CTR с помощью одной из следующих функций:
- HMAC-SHA1
- HMAC-SHA-256
- HMAC-SHA-512
- режим GCM
Для инициализации любых криптографических ключей, сгенерированных KeyGenerator , используйте надежный генератор случайных чисел, SecureRandom . Использование ключа, не сгенерированного с помощью надежного генератора случайных чисел, значительно ослабляет надежность алгоритма и может позволить проводить атаки в автономном режиме.
Если вам необходимо хранить ключ для многократного использования, воспользуйтесь механизмом, таким как KeyStore , который обеспечивает долговременное хранение и извлечение криптографических ключей.
Межпроцессное взаимодействие
Некоторые приложения пытаются реализовать межпроцессное взаимодействие (IPC) с использованием традиционных методов Linux, таких как сетевые сокеты и общие файлы. Однако мы рекомендуем вместо этого использовать системные функции Android для IPC, такие как Intent , Binder или Messenger с Service , а также BroadcastReceiver . Механизмы IPC в Android позволяют проверять подлинность приложения, подключающегося к вашему IPC, и устанавливать политику безопасности для каждого механизма IPC.
Многие элементы безопасности используются совместно различными механизмами межпроцессного взаимодействия (IPC). Если ваш механизм IPC не предназначен для использования другими приложениями, установите атрибут android:exported в значение false в элементе манифеста компонента, например, для элемента <service> . Это полезно для приложений, состоящих из нескольких процессов в рамках одного UID, или если вы на поздней стадии разработки решите, что на самом деле не хотите предоставлять функциональность через IPC, но не хотите переписывать код.
Если ваш межпроцессный доступ (IPC) доступен другим приложениям, вы можете применить политику безопасности, используя элемент <permission> . Если IPC осуществляется между вашими приложениями, подписанными одним и тем же ключом, используйте разрешение signature-level в android:protectionLevel .
Намерения
Для активностей и широковещательных приемников предпочтительным механизмом асинхронного межпроцессного взаимодействия в Android являются интенты. В зависимости от требований вашего приложения вы можете использовать sendBroadcast , sendOrderedBroadcast или явное указание интента для конкретного компонента приложения. В целях безопасности предпочтительнее использовать явные интенты.
Обратите внимание, что упорядоченные широковещательные сообщения могут быть обработаны получателем, поэтому они могут быть доставлены не всем приложениям. Если вы отправляете намерение, которое должно быть доставлено конкретному получателю, необходимо использовать явное намерение, в котором получатель указан по имени.
Senders of an intent can verify that the recipient has permission by specifying a non-null permission with the method call. Only applications with that permission receive the intent. If data within a broadcast intent might be sensitive, consider applying a permission to make sure that malicious applications can't register to receive those messages without appropriate permissions. In those circumstances, you might also consider invoking the receiver directly, rather than raising a broadcast.
Услуги
A Service is often used to supply functionality for other applications to use. Each service class must have a corresponding <service> declaration in its manifest file.
By default, services aren't exported and can't be invoked by any other application. However, if you add any intent filters to the service declaration, it is exported by default. It's best if you explicitly declare the android:exported attribute to be sure it behaves the way you intend it to. Services can also be protected using the android:permission attribute. By doing so, other applications need to declare a corresponding <uses-permission> element in their own manifest to be able to start, stop, or bind to the service.
A service can protect individual IPC calls that are made into it with permissions. This is done by calling checkCallingPermission() before executing the implementation of the call. We recommend using the declarative permissions in the manifest, since those are less prone to oversight.
Binder and Messenger interfaces
Using Binder or Messenger is the preferred mechanism for RPC style IPC on Android. They provide well-defined interfaces that enable mutual authentication of the endpoints, if required.
We recommend that you design your app interfaces in a way that doesn't require interface-specific permission checks. Binder and Messenger objects aren't declared within the application manifest, and therefore you can't apply declarative permissions directly to them. They generally inherit permissions declared in the application manifest for the Service or Activity within which they are implemented. If you are creating an interface that requires authentication and/or access controls, you must explicitly add those controls as code in the Binder or Messenger interface.
If you are providing an interface that does require access controls, use checkCallingPermission() to verify whether the caller has a required permission. This is especially important before accessing a service on behalf of the caller, as the identity of your application is passed to other interfaces. If you are invoking an interface provided by a Service , the bindService() invocation can fail if you don't have permission to access the given service. If you need to allow an external process to interact with your app but it doesn't have the necessary permissions to do so, you can use the clearCallingIdentity() method. This method performs the call to your app's interface as though your app were making the call itself, rather than the external caller. You can restore the caller permissions later with the restoreCallingIdentity() method.
For more information about performing IPC with a service, see Bound Services .
Broadcast receivers
A BroadcastReceiver handles asynchronous requests initiated by an Intent .
By default, receivers are exported and can be invoked by any other application. If your BroadcastReceiver is intended for use by other applications, you might want to apply security permissions to receivers using the <receiver> element within the application manifest. This prevents applications without appropriate permissions from sending an intent to the BroadcastReceiver .
Security with dynamically loaded code
We strongly discourage loading code from outside of your application APK. Doing so significantly increases the likelihood of application compromise due to code injection or code tampering. It also adds complexity around version management and application testing—and it can make it impossible to verify the behavior of an application, so it might be prohibited in some environments.
If your application does dynamically load code, the most important thing to keep in mind is that the dynamically loaded code runs with the same security permissions as the application APK. The user makes a decision to install your application based on your identity, and the user expects that you provide any code run within the application, including code that is dynamically loaded.
Many applications attempt to load code from insecure locations, such as downloaded from the network over unencrypted protocols or from world-writable locations such as external storage. These locations could let someone on the network modify the content in transit or another application on a user's device to modify the content on the device. On the other hand, modules included directly within your APK can't be modified by other applications. This is true whether the code is a native library or a class being loaded using DexClassLoader .
Security in a virtual machine
Dalvik is Android's runtime virtual machine (VM). Dalvik was built specifically for Android, but many of the concerns regarding secure code in other virtual machines also apply to Android. In general, you don't need to concern yourself with security issues relating to the virtual machine. Your application runs in a secure sandbox environment, so other processes on the system can't access your code or private data.
If you're interested in learning more about virtual machine security, familiarize yourself with some existing literature on the subject. Two of the more popular resources are:
This document focuses on areas that are Android specific or different from other VM environments. For developers experienced with VM programming in other environments, there are two broad issues that might be different about writing apps for Android:
- Some virtual machines, such as the JVM or .NET runtime, act as a security boundary, isolating code from the underlying operating system capabilities. On Android, the Dalvik VM is not a security boundary—the application sandbox is implemented at the OS level, so Dalvik can interoperate with native code in the same application without any security constraints.
- Given the limited storage on mobile devices, it's common for developers to want to build modular applications and use dynamic class loading. When doing this, consider both the source where you retrieve your application logic and where you store it locally. Don't use dynamic class loading from sources that aren't verified, such as unsecured network sources or external storage, because that code might be modified to include malicious behavior.
Security in native code
In general, we recommend using the Android SDK for application development, rather than using native code with the Android NDK . Applications built with native code are more complex, less portable, and more likely to include common memory-corruption errors such as buffer overflows.
Android is built using the Linux kernel, and being familiar with Linux development security best practices is especially useful if you are using native code. Linux security practices are beyond the scope of this document, but one of the most popular resources is Secure Programming HOWTO - Creating Secure Software .
An important difference between Android and most Linux environments is the application sandbox. On Android, all applications run in the application sandbox, including those written with native code. A good way to think about it for developers familiar with Linux is to know that every application is given a unique User Identifier (UID) with very limited permissions. This is discussed in more detail in the Android Security Overview , and you should be familiar with application permissions even if you are using native code.