Введення пароля при виклику API REST


31

Припустимо, у мене є API REST, який також використовується для встановлення / скидання паролів. Припустимо також, що це працює через HTTPS-з'єднання. Чи є якась вагома причина не вставити цей пароль у шлях виклику, скажімо також, що я кодую його в BASE64?

Прикладом може бути скидання пароля таким чином:

http://www.example.com/user/joe/resetpassword/OLDPASSWD/NEWPASSWD

Я розумію, що BASE64 - це не шифрування, але я хочу лише захистити пароль для серфінгу через плечі.


61
Чи пропонуєте ви побічні ефекти щодо GET? Це порушення протоколу саме там.
Есбен Сков Педерсен

27
Це насправді не REST, оскільки resetpassword/OLDPASSWD/NEWPASSWDце не ресурс. Це виклик процесу. Вам не потрібно все вкладати в URL.
usr

5
@Esben: хто сказав, що це GET? ОП ніколи цього не казала.
dagnelies

3
Щоправда, він не ставив питання. Але його коментар до відповіді Нетха говорить "Звичайно, мені доведеться використовувати POST зрештою", тому ми можемо припустити, що він спочатку мав намір / запитав про GET. Що, як зазначає Есбен, - погана річ. GET повинен читати лише
Mawg

Відповіді:


76

Хороший сервер реєструє всі надіслані до нього запити, включаючи URL-адреси (часто, без змінної частини після '?'), Вихідний IP-код, час виконання ... Чи дійсно ви хочете, щоб цей журнал (потенційно прочитаний широкою групою адміністраторів) містив критично захищена інформація як паролі? Base64 не є пробкою проти них.


42
Це не найбільша причина використання POST. Це причина безпеки. Але як Есбен вже зауважив у коментарях, зміна стану з GET є порушенням такої послуги відпочинку
Pinoniq

2
@BartFriederichs: і історія браузера запам'ятала б URL-адресу. І анонімно випробовуючи купу паролів, зробивши веб-сторінку, на якій є посилання на всі паролі, які ви хочете спробувати, і дозволити Googlebot робити фактичні запити ...
RemcoGerlich

2
"Але коли Esben все-таки відзначає коментарі, зміна стану з GET є порушенням такої послуги відпочинку" Я також помітив цей коментар, але я не бачу, де хтось говорить, що це був запит GET. Ви можете вбудувати інформацію в URI і все-таки розмістити її. Це насправді не RESTful , оскільки URI насправді не називає ресурс.
Джошуа Тейлор

Привіт, хороша відповідь, але я не згоден з "без змінної частини після"? "" ... Є багато багатьох, які зберігають повну URL-адресу !!!
dagnelies

2
"зміна стану на GET - це порушення такої послуги відпочинку" - Не давайте занадто захоплюватися REST. Зміна стану за допомогою GET є порушенням HTTP .
Дан Елліс

69

Те, що ви пропонуєте, не є ані безпечним, ані РЕЗЕРАЦІЙним.

@Netch вже згадував про проблему з журналами, але є й інша проблема в тому, що ви показуєте паролі, що надсилаються HTTP, що робить тривіальним захоплення паролів будь-яким дротяним снайфером або атакою людини в середині.

Коли ви робите запит GET, використовуючи REST, різні елементи в URL-адресі представляють більш дрібнозернисті елементи. Ваша URL-адреса звучить так, як ви повертаєте NEWPASSWD частину OLDPASSWD, що є частиною перезапущеного слова. Це не має ніякого смислового сенсу. GET не слід використовувати для збереження даних.

Ви повинні робити щось подібне:

POST https://www.example.com/user/joe/resetpassword/
{oldpasswd:[data], newpasswd:[data]}

POST тому, що ви записуєте дані, а https - тому що ви не хочете, щоб вони нюхали.

(Це дійсно низький рівень захисту. Абсолютний мінімум, який ви повинні зробити.)


2
Чи не означало б це хешування паролів на стороні клієнта? Це рекомендується?
Роуан Фрімен

1
Примітка. Це не дозволить виконувати вимоги щодо пароля (довжини тощо). Це може не бути проблемою у вашому випадку, хоча це є частою практикою безпеки, а іноді цього вимагають деякі організації.
Пол Дрейпер

8
Ви не створюєте нову запис, але оновлюєте існуючий запис (як правило), тому це має бути PUT, а не POST.

4
Це не дуже ВІДПОВІДНО. resetpassword - це не ресурс, не кажучи вже про підресурс. Однак /user/joe/passwordтрохи краще, але не оптимально.
вихор

12
@CamilStaps Ні, ви не можете використовувати PUT, тому що PUTє idempotent. Але коли пароль було змінено з secretна supersecretуспішно, то той самий запит буде відмовлено вдруге, тому POSTтут правильно. Звичайно, як сказав @whirlwin, цей ресурс не так добре названий.
Residuum

60

Запропонована схема має проблеми у кількох сферах.

Безпека

URL-шляхи часто реєструються; ставити незахищені паролі на шляху - це погана практика.

HTTP

Інформація про автентифікацію / авторизацію повинна відображатися в заголовку авторизації. Або, можливо, для базованих на веб-переглядачах заголовка Cookie.

ВІДПОВІДНИЙ

Такі дієслова, як resetpasswordу вашій URL-адресі, як правило, явна ознака парадигми передачі стану, що не є представником. URL-адреса повинна представляти ресурс. Що це означає GETresetpassword ? Або ВИДАЛИТИ?

API

Ця схема вимагає завжди знати попередній пароль. Ви, ймовірно, захочете дозволити більше справ; наприклад, пароль втрачено.


Ви можете використовувати базову або дайджест аутентифікацію , що добре зрозумілі схеми.

PUT /user/joe/password HTTP/1.0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: text/plain
Host: www.example.com

NEWPASSWD

Він не ставить надто чутливу інформацію на шляху, і вона дотримується конвенцій HTTP та REST.

Якщо вам потрібно було дозволити якийсь інший режим авторизації (наприклад, якийсь маркер, надісланий через перевірений канал для скидання пароля), ви можете просто використовувати інший заголовок авторизації, не змінюючи нічого іншого.


4

Крім безпеки, проблема в тому, що це не дуже RESTful підхід.

OLDPASSWD і NEWPASSWD не стоїте ні перед чим у вашій ієрархії ресурсів, а ще гірше, що операція не є безсильною.

Таким чином, ви можете використовувати лише POSTяк своє дієслово, і ви не повинні включати два паролі у ваш ресурсний шлях.


1
Ви не створюєте нову запис, але оновлюєте існуючий запис (як правило), тому це має бути PUT, а не POST.

2
@CamilStaps Якщо це тільки встановлення пароля, це може бути. Але оскільки, мабуть, і старий пароль теж повинен бути перевірений, він робить операцію неідентичною, і тому PUTдискваліфікується як дієслово. Працювати з нею можна, PUTале в теперішньому вигляді це не так.
biziclop

OLDPASSWD - це інформація про автентифікацію, і вона взагалі не повинна містити URL-адресу.

Не обов'язково звичайна практика явно запитувати старий пароль поверх аутентифікації.
biziclop

3

Проблема полягає у тому, щоб у ваших запитах уникати звичайних текстових паролів. Є два варіанти виконання спокійних вимог веб-сервісу.

1. Хеширование на стороні клієнта

  • Я думаю, ви зберігаєте ваші паролі, наприклад хеш (пароль + сіль)
  • Новий пароль можна засипати сіллю на стороні клієнта
  • Це означає: Створіть нову сіль на стороні клієнта, створіть хеш, наприклад хеш (newPassword + newSalt)
  • Надішліть новий створений хеш плюс сіль на ваш спокійний веб-сервіс
  • Надішліть старий пароль також як хеш (oldPassword + oldSalt)

2. Шифрування

  • Створіть ресурс "one time key" (otk) для користувача типу / otk / john
  • Цей ресурс повертає захищений випадковий унікальний одноразовий ключ, наприклад kbDlJbmNmQ0Y0SmRHZC9GaWtRMW0ycVJpYzhMcVNZTWlMUXN6ZWxLdTZESFRs та унікальний ідентифікатор, наприклад 95648915125
  • Ваша спокійна веб-служба повинна зберігати цей випадковий otk для наступного безпечного спілкування з ідентифікатором 95648915125
  • Зашифруйте свій новий і старий пароль за допомогою otk, наприклад AES (з міркувань безпеки слід використовувати два окремі otks для старого та нового пароля)
  • Надішліть зашифровані паролі на свій ресурс зміни пароля з ідентифікатором 95648915125
  • Одна комбінація otk та ID може працювати лише один раз, тому після зміни пароля її потрібно видалити
  • Можливий кращий варіант: Надішліть поточний / старий пароль від Basic-Auth.

Примітка: HTTPS необхідний для обох варіантів!


1
Чому б я подвійно шифрував (ваша схема шифрування за допомогою OTK та HTTPS) обмін паролем? Який вектор атаки тут не охоплений HTTPS?
Барт Фрідеріхс

1
Єдина мета - уникнути можливих журналів сервера. Тіло запиту HTTP (наприклад, з новим паролем прямого тексту) також може бути зареєстровано, хоча HTTPS використовується. Інша можлива атака - використання самопідписаного сертифіката, який особливо використовується для внутрішніх цілей.
maz258

2

Які особливості операції скидання пароля?

  1. Це щось змінює.
  2. Є значення, яке воно встановлено.
  3. Лише деякі люди можуть це робити (користувач, адміністратор або будь-яке, можливо, з різними правилами щодо того, як це можна зробити).

Точка 1 тут означає, що ви не можете використовувати GET, вам потрібно або POST щось, що представляє операцію зміни пароля, на URI, що представляє ресурс, який обробляє зміни пароля, або ВИПУСИТИ щось, що представляє новий пароль для URI, що представляє пароль або щось, що представляє (наприклад, користувач), для якого цей пароль є функцією.

Як правило, ми б розмістили POST, не в останню чергу тому, що це може бути незручно ВИПУСКУВАННЯ чогось, що ми не можемо пізніше отримати, і, звичайно, ми не можемо отримати пароль.

Отже, у пункті 2 будуть дані, що представляють новий пароль у тому, що POSTed.

Пункт 3 означає, що нам потрібно авторизувати запит, а це означає, що, якщо користувач є поточним користувачем, нам знадобиться підтвердити поточний пароль (хоча це не обов'язково отримати поточний пароль, якщо, наприклад, виклик на основі хешу використовувався для доведення знань про це, не надсилаючи).

Отже, URI повинен бути чимось на зразок <http://example.net/changeCurrentUserPassword>або<http://example.net/users/joe/changePassword> .

Ми можемо вирішити, що хочемо отримати поточний пароль у даних POST, а також у загальному механізмі авторизації, який використовується.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.