Возник вопрос, как правильно и безопасно реализовать авторизацию в приложении Android на удаленном сервере с REST (по крайней мере, хотелось бы в это верить :)) API, написанном на PHP.
Сейчас схема следующая:
1. Пользователь вводит логин и пароль, они с помощью POST запроса отправляются на сервер (адрес вида www.mysite.com/api/v1/login).
2. Если все ок (логин и пароль верные) - сервер возвращает информацию о пользователе (имя, дата регистрации и т.д.) наряду с ApiKey - этот ключ генерируется случайным образом в момент регистрации пользователя.
3. Все операции в приложении происходят с использованием этого ApiKey - он отдается серверу в заголовке GET/POST/PUT запроса в поле Authorization. Сервер смотрит его в БД, если не находит - выдает HTTP 401.
Необходимо реализовать некий механизм в приложении вроде галочки "Запомнить меня". Т.е. если пользователь успешно залогинился - не спрашивать его больше логин и пароль, пока он принудительно не нажмет некую кнопочку "Выйти". Хранить связку логин/пароль в SharedPreferences или sqlite небезопасно, также как и хранить там ApiKey.
Подскажите, пожалуйста, если ли какие-то специально для этого предназначенные места? Или, может быть, собака зарыта где-то в другом месте?
Я сейчас делаю так. логинится пользователь, создаем сессию для него, ключ сессии - в куки. Вметсе с ним в куки зашифрованный функцией crypt токен - его в базу. закончилась сессия - расшифровываем токен и проверяем. нормально - выдаем новый сес ключ, не подходит - пошел вон)
Сергей Протько: токен передаем только по запросу, что сессия кончилась) умнее придумать не смог) если бы подсказали, как сделать лучше, с радостью бы прислушался)
Т.е. будет 2 авторизации на сервере: 1 по логину+паролю, 2ая по хешу логина и хешу пароля? Если я правильно понял, то не составит труда также достать эти хеши и получить доступ к серверу с помощью них.
Нет! Я делаю в таких ситуациях так, ApiKey - временный скажем 10 мин. Для авторизация также использвется hash = sha256(login:pass). Во время авторизации сервер выдает ApiKey. После получения 401 мы отправляем на сервеор для проделия аренды. На случай повышения безопасности так же рекомендую вы давай вместе с ApiKey, NextToken- случайный набор бит, после этого, т.е. когда мы продляем аренду ключа, мы высылаем hash = des(sha256(login,pass),NextToken) и так далее пока пользователь не нажмет выйти
т.е. при каждом вызове www.mysite.com/api/v1/login скрипт на сервере смотрит разницу (сейчас минус apikey_timestamp) и если она больше 10 мин то создает новый рандомный ApiKey?
Не совсем понял про "После получения 401 мы отправляем на сервеор для проделия аренды.", можно поподробнее?
@ape364, в случае если время жизни нашего токена истекло, апишка должна ругаться ошибкой 401 not authorized. В этом случае на стороне клиента мы можем обработать эту ситуацию - отправляем запрос на продление жизни токена (по сути выделение нового), заменяем у себя токен и старый хэш на новый заменяем для возможности и потом продлить время жизни токена, ну и повторяем запрос.
Если при получении нового токена сервер его не дал, значит у нас не правильный хэш и мы должны попросить пользоваться авторизоваться.
Интересно, из каких размышлений исходили когда придумали штуку с ApiKey который генерируется 1 раз при регистрации?
Пароль и логин не хранят на клиенте все верно. ApiKey ваш, тоже.
Посмотрите на то как реализована авторизация у сложных систем, ведь у них везде есть токен сессии. Рекомендую и вам его использовать.
Схема такая: на сервере, как то, где то храните токены пользователей. У токена есть время завершения сессии. например пару дней.
При каждом запросе передается этот токен и продлеваете время сессии, на текущее время + ваш срок истечения сессии. Если передали устаревший токен, пишите в лог подозрительные данные.
Получается такая ситуация. Пользователь активный - можно авторизоваться лишь раз.
Пользователь заходит раз в неделю, что уж извольте авторизуйтесь. Токен само собой хранить на устройстве и желательно его зашифровать.
Используйте HTTPS, но можно еще и такое придумать. Ключ шифрования - ваш ApiKey который знает устройство и знает сервер. В таком случае при передаче через сеть он непонятен.
в таком случае, если пользователь будет мало активен, продлите до двух недель сессию. и если сервис не так и активно пользуется, есть ли смысл в безопастности? если есть, пускай вводит логин пароль.
но есть еще вариант, авторизация через гугл акк или еще что. со стороны пользователя нужно будет только нажать "да принимаю" и все
Порядок такой:
1. Пользователь ввел логин и пароль, отправил их на сервер.
2. Если они верные, то на сервере генерируется некий случайный токен и записывается вместе с датой окончания (сейчас плюс время действия) в табличку с пользователями в некие поля token & token_expires.
3. Токен отдается в JSON обратно клиенту.
4. Клиент записывает этот токен куда-то на устройство и все запросы отсылает, приложив этот самый токен.
Если получен токен с истекшим сроком действия - клиент отправляется на окно авторизации для ввода логина и пароля, так?
Т.е. по сути этот тот же apikey, который хранится на устройстве, только он имеет срок действия?
API KEY, который генерируется при регистрации, можно вообще ему срок годности не задавать, просто токен, который всегда действителен, единственное можно написать функцию для смены этого токена, ну если пользователи захочет.