Найкращий підхід для генерації ключа API


89

Отже, зараз існує безліч різноманітних сервісів, API Google, Twitter API, Facebook API тощо.

Кожна служба має ключ API, наприклад:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

Всі ключі різняться за довжиною та символами, які вони містять, мені цікаво, який найкращий підхід для створення ключа API?

Я не запитую конкретну мову, а лише загальний підхід до створення ключів, чи це шифрування деталей програми користувачів, чи хеш, чи хеш випадкового рядка тощо. Чи варто нам турбуватися про хеш-алгоритм (MSD, SHA1, bcrypt) тощо?

Редагувати: Я спілкувався з кількома друзями (електронною поштою / твіттером), і вони рекомендували просто використовувати GUID із позбавленими тире.

Мені це здається трохи хакі, сподіваючись отримати ще кілька ідей.


Відповіді:


58

Використовуйте генератор випадкових чисел, призначений для криптографії. Потім base-64 закодує номер.

Це приклад на C #:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
    generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);

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

13
Зберігання випадково сформованого ключа API має ті ж характеристики безпеки, що і зберігання хешованого пароля. У більшості випадків це нормально. Як ви пропонуєте, можна вважати випадково сформоване число соллю та хешуванням його із серверним секретом; однак, роблячи це, ви отримуєте хеш-витрати на кожну перевірку. Також неможливо визнати недійсним секрет сервера без анулювання всіх ключів API.
Едвард Брей,

Гарне рішення, але вам потрібно ключове слово var перед apiKey, ймовірно :) var apiKey = Convert.ToBase64String (ключ);
Dawid Ohia 01.03.18

@ JohnM2 Правильно. Я залишав його відкритим, оскільки його apiKeyможна було декларувати деінде. Я додав тип для наочності.
Едвард Брей,

4
@JamesWierzba, якщо атакований вже є у вашій базі даних, то, маючи незахищений доступ до вашого API, це, мабуть, найменше з ваших проблем ...
Джон Історія,

29

Ключі API повинні мати такі властивості:

  • однозначно ідентифікувати авторизованого користувача API - "ключову" частину "API-ключа"
  • автентифікувати цього користувача - неможливо вгадати / підробити
  • може бути скасовано, якщо користувач неналежним чином поводиться - зазвичай вони вводять дані в базу даних, яка може мати видалений запис.

Зазвичай у вас буде тисячі або мільйони ключів API, а не мільярди, тому їм не потрібно:

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

Таким чином, один із способів створення ключа API - це взяти дві частини інформації:

  1. серійний номер, що гарантує унікальність
  2. достатньо випадкових біт, щоб вибити ключ

і підпишіть їх, використовуючи приватну таємницю.

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

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


або хеш випадкового рядка

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


3
Чи необхідний крок підписання вашого алгоритму, якщо ключ API, представлений клієнтом, перевіряється з базою даних вже зареєстрованих ключів API на сервері, що надає API? Здається, підписання тут було б зайвим, якщо сервер надає ключі.
саппенін

3
@sappenin, так. Якщо ви зберігаєте на сервері недоступний ключ, то вам не потрібно запобігати підробці. Часто запити API обробляється будь-яким з ферми машин - сервер є одним з багатьох серверів. Перевірку підписів можна здійснити на будь-якій машині без зворотного переходу до бази даних, яка в деяких випадках дозволяє уникнути перегонових умов.
Mike Samuel

1
@MikeSamuel, якщо ключ API підписаний, і ви не робите зворотну поїздку до бази даних, що відбувається, коли ключ відкликано, але все ще використовується для доступу до API?
Абхюдіт Джейн

@AbhyuditJain, У будь-якій розподіленій системі потрібен послідовний порядок повідомлень (відкликання відбувається до наступного використання скасованих облікових даних) або інші способи обмеження двозначності. Деякі системи не обертаються в обидва кінці за кожним запитом - якщо вузол зафіксує той факт, що ключ був у базі даних протягом 10 хвилин, існує лише 10 хвилин. вікно, в якому зловмисник може зловживати скасованими обліковими даними. Однак можлива плутанина: користувач анулює облікові дані, потім перевіряє, що їх анульовано, і дивується тому, що нелипкі сеанси змушують два запити переходити до різних вузлів.
Mike Samuel

5

Я використовую UUID, відформатовані малими літерами без тире.

Покоління легко, оскільки більшість мов це вбудували.

Ключі API можуть бути скомпрометовані, і в цьому випадку користувач може захотіти скасувати свій ключ API і сформувати новий, тому ваш метод генерації ключів повинен відповідати цій вимозі.


15
Не вважайте, що UUID важко вгадати; їх не слід використовувати як засоби безпеки (UUID специфікація RFC4122, розділ 6 ). Ключ API потребує захищеного випадкового числа, але UUID не є надійно невідповідними .
Едвард Брей,

3
@EdwardBrey як щодо UUID uuid = UUID.randomUUID();Java? Ви хочете сказати, що випадкові дії недостатньо хороші?
Micro

8
@MicroR Випадковий UUID захищений лише у тому випадку, якщо генератор випадкових чисел, який використовується для його створення, є криптографічно захищеним і достатньо 128 бітів. Хоча UUID RFC не вимагає захищеного генератора випадкових чисел, певна реалізація може використовувати його. У випадку з randomUUID , у документах API конкретно зазначено, що він використовує "криптографічно сильний генератор псевдовипадкових чисел". Таким чином, конкретна реалізація є безпечною для 128-розрядного ключа API.
Едвард Брей,

4

Якщо вам потрібен ключ API лише з буквено-цифровими символами, ви можете використовувати варіант підходу base64-random , замість цього використовуючи лише кодування base-62. База-62 датчик заснований на цьому .

public static string CreateApiKey()
{
    var bytes = new byte[256 / 8];
    using (var random = RandomNumberGenerator.Create())
        random.GetBytes(bytes);
    return ToBase62String(bytes);
}

static string ToBase62String(byte[] toConvert)
{
    const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    BigInteger dividend = new BigInteger(toConvert);
    var builder = new StringBuilder();
    while (dividend != 0) {
        dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
        builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
    }
    return builder.ToString();
}

1

Ключ API повинен мати деяке випадкове значення. Досить випадково, що його неможливо передбачити. Він не повинен містити жодних даних про користувача чи обліковий запис, для якого він призначений. Використання UUID - це гарна ідея, якщо ви впевнені, що створені ідентифікатори є випадковими.

Наприклад, у більш ранніх версіях Windows були передбачувані GUID, але це стара історія.


4
Windows 2000 перейшла на GUID, використовуючи випадкові числа . Однак немає гарантії, що випадкові числа неможливо передбачити. Наприклад, якщо зловмисник створює для себе кілька ключів API, можливо, можна буде визначити майбутнє випадкове число, що використовується для генерації ключа API іншого користувача. Загалом, не вважайте UUID безпечно недоступними .
Едвард Брей,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.