Как проверить, что вызовы сервера сделаны из приложения?

У меня есть приложение для Android, которому необходимо часто подключаться к серверу для извлечения или добавления в базу данных разумных данных. Мне нужно было проверить, что вызовы на сервер, где они сделаны из приложения, поэтому я использовал этот подход: как проверить личность клиента с сервера? который состоит из жестко заданного строкового ключа в приложении, который проверен на сервере. Но потом я понял, что есть такие инструменты, как dex2jar, которые будут показывать весь мой код (даже с некоторой запутанностью от proguard), в частности, этот жесткий код.

Есть ли более элегантный и безопасный способ проверить, что вызовы сервера сделаны из моего приложения?

PS: Прошу прощения за английский, я явно не носитель языка.

Если это только ваш клиент и ваш сервер, вы можете (и должны) использовать взаимно аутентифицированный SSL, не покупая ничего. Вы управляете сервером и клиентом, поэтому каждый должен доверять только одному сертификату, другому, принадлежащему другому, и для этой цели вам не нужны CA.

Вот высокоуровневый подход. Создайте сертификат SSL с самозаверяющим сервером и разверните его на своем веб-сервере. Для этой цели вы можете использовать keytool, входящий в комплект Android SDK. Затем создайте самозаверяющий клиент и разверните его в своем приложении в настраиваемом хранилище ключей, включенном в ваше приложение, в качестве ресурса (keytool также генерирует это приложение). Настройте сервер, требующий аутентификации на стороне клиента, и только принять сертификат клиента, который вы создали. Настройте клиента для использования этого сертификата на стороне клиента для идентификации себя и принимайте только тот серверный сертификат, который вы установили на своем сервере для этой части.

Шаг за шагом для этого – гораздо более длинный ответ, чем это можно сделать здесь. Я бы предложил сделать это поэтапно, так как в Интернете есть ресурсы о том, как работать с самоподписанным сертификатом SSL на Android, как на стороне сервера, так и на стороне клиента. В моей книге «Безопасность приложений для платформы Android», опубликованной O'Reilly, также есть полная версия.

Обычно вы храните этот сертификат / закрытый ключ в хранилище ключей sometype (KeyStore, если вы используете Android), и что хранилище ключей будет зашифровано. Это шифрование основано на пароле, поэтому вам нужно либо (1) сохранить этот пароль в своем клиенте где-нибудь, либо (2) попросить пользователя пароль при запуске вашего клиентского приложения. То, что вам нужно сделать, зависит от вашего использования. Если (2) является приемлемым, тогда вы защитили свои учетные данные от обратного проектирования, поскольку он будет зашифрован и пароль не будет храниться нигде (но пользователю нужно будет вводить его каждый раз). Если вы это сделаете (1), тогда кто-то сможет перепроектировать вашего клиента, получить пароль, получить хранилище ключей, расшифровать закрытый ключ и сертификат и создать другого клиента, который сможет подключиться к серверу.

Вы ничего не можете сделать, чтобы это предотвратить; вы можете сделать обратное проектирование вашего кода сложнее (путем обфускации и т. д.), но вы не можете сделать это невозможным. Вам нужно определить, какой риск вы пытаетесь смягчить с помощью этих подходов, и сколько работы стоит сделать для его смягчения.