Безопасность веб-API

Мне предлагается написать веб-API для приложения (pc executable, не веб-приложение), которое позволит отправлять электронные письма.
Пользователь нажимает что-то, приложение связывается с API, который генерирует электронное письмо и отправляет его.

Я должен убедиться, что никто из несанкционированных пользователей не получит доступ к API, поэтому мне нужно сделать некоторую аутентификацию, и у меня нет идеи, как это сделать правильно.

Будет больше приложений, обращающихся к API.

Первая мысль - отправить имя пользователя и пароль, но это не решит проблему. Потому что, если кто-то декомпилирует приложение, они будут иметь URL-адрес запроса и переменные, включая пользователя/пароль, или просто его можно просто понюхать.

Итак... какие у меня варианты?

Я уверен, что безопасное соединение (SSL) недоступно мне в данный момент, но все же это не поможет мне в решении проблемы декомпиляции, не так ли?


ИЗМЕНИТЬ

Я не сказал, что изначально, но пользователь не будет запрашивать имя пользователя/пароль. Это приложение (приложения), которое должно быть аутентифицировано, а не пользователи приложения (ов).

Ответ 1

Я бы порекомендовал вам проверить OAuth. он определенно поможет вам разобраться в проблемах безопасности с авторизацией инструментов для доступа к вашему API.

http://oauth.net

Ответ 2

Распределение вашего программного обеспечения на самом деле является основной проблемой. Хеширование имен пользователей и паролей и их сохранение в программном обеспечении не более полезно, чем хранение не хэшированных значений, так как любой из них будет работать для доступа к серверу API. Если вы собираетесь внедрять имена пользователей и пароли для своих пользователей, я думаю, вы можете использовать это как предварительный указатель на управление API, не сохраняя значения в самом программном обеспечении. Позвольте мне описать это в двух частях.

Запросить подписи

Наиболее распространенным методом, используемым для проверки запроса API, является сигнатура запроса. В принципе, перед отправкой запроса на сервер API параметры в запросе сортируются, и в микс добавляется уникальный ключ. Затем вся партия используется для создания хэша, который добавляется к запросу. Например:

public static function generateRequestString(array $params, $secretKey)
{
    $params['signature'] = self::generateSignature($params, $secretKey);
    return http_build_query($params,'','&');
}

public static function generateSignature($secretKey, array $params)
{
    $reqString = $secretKey;
    ksort($params);
    foreach($params as $k => $v)
    {
        $reqString .= $k . $v;
    }
    return md5($reqString);
}

Вы можете создать строку запроса запроса API, используя вышеуказанный код, просто вызвав метод generateRequestString() с массивом всех параметров, которые вы хотите отправить. Секретный ключ - это то, что предоставляется уникально каждому пользователю API. Как правило, вы передаете свой идентификатор пользователя на сервер API вместе с подписью, а сервер API использует ваш идентификатор для извлечения секретного ключа из локальной базы данных и проверки запроса так же, как вы его создали. Предполагая, что ключ и идентификатор пользователя верны, этот пользователь должен быть единственным, кто может создать правильную подпись. Обратите внимание, что ключ никогда не передается в запросе API.

К сожалению, для каждого пользователя требуется уникальный ключ, который является проблемой для вашего настольного приложения. Это приводит меня к шагу два.

Временные ключи

Таким образом, вы не можете распространять ключи с приложением, потому что их можно декомпилировать, и ключи будут уходить. Чтобы противодействовать этому, вы могли бы сделать очень короткоживущие ключи.

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

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

Резюме

Если вы можете установить временный ключ сеанса, вам не нужно хранить что-либо в клиентской программе, которую можно декомпилировать. Имя пользователя/пароль, отправленные один раз на ваш сервер, должно быть достаточно, чтобы установить это. После того, как у вас есть этот ключ, вы можете использовать его для создания запросов в настольных приложениях и проверки запросов на сервере API.

Ответ 3

Кто-то всегда сможет декомпилировать и искать переменные. Обфускатор может скрыть их немного лучше. Sniffing также легко без SSL, если вы не используете частный и открытый набор ключей для шифрования клиентской части данных запроса и расшифровки серверной части (но, очевидно, этот ключ будет храниться в клиентском приложении).

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

http://www.codeproject.com/KB/security/SecureStream.aspx

Как упоминалось mattjames, вы никогда не должны хранить пароли в текстовом формате. Когда пользователь вводит свой пароль в приложение, храните хеш пароля. Тот же хеш должен храниться на сервере. Таким образом, если хеш рассматривается перехватчиком, они, по крайней мере, не будут видеть исходный пароль пользователя.

Ответ 4

Вам нужно будет использовать SSL, если вам нужно, чтобы люди не видели простой текстовый пароль, который отправляется из приложения по сети в API.

Для проблемы декомпиляции вам нужно сохранить хэш пароля в API, а не исходный пароль. См. Объяснение здесь: http://phpsec.org/articles/2005/password-hashing.html.