Подтвердить что ты не робот

Схема единого символьного подписания (минимальная безопасность)

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

Ситуация

Система A:

У меня есть система A, которая обслуживает запросы пользователей. Этот сервер что-то делает, а затем перенаправляет пользователя в систему B. Во время этого перенаправления сервер A может предоставить пользователю 32-значную буквенно-цифровую строку информации для передачи в систему B. Для этого требуется 31 символ этой информации, но ее можно использовать в качестве контрольной суммы. Эта строка более или менее может считаться идентификатором запроса.

Система B:

Когда система B получает запрос от пользователя, он может проверить, что запрос (и строка, подобная ID) действителен, анализируя 31-символьную строку, запрашивая базу данных и разговаривая с системой A. Это система может с абсолютной уверенностью проверить, что запрос действителен и не был подделан, но он очень дорого стоит вычислить.

Нападающие:

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

Что мне нужно

Я ищу схему контрольной суммы/подписи, которая может с одним символом дать мне хорошее представление о том, должен ли запрос продолжать процесс проверки или если он должен быть немедленно отброшен как недействительный. Если сообщение отбрасывается, я должен быть на 100% уверен, что он недействителен, но это нормально, если я сохраняю недопустимые сообщения. Я считаю, что идеальным решением будет означать, что 1/62 недействительных запросов хранится (злоумышленник должен угадать символ проверки), но в качестве минимального решения было бы отброшено половина всех недопустимых запросов.

Что я пробовал

Я рассмотрел использование алгоритма Луна (тот же, что использовался для кредитных карт), но я хотел бы иметь возможность использовать ключ для генерации персонажа, чтобы сделать его более трудным для подмены контрольной суммы. /p >

Как первая попытка создания схемы подписи, я поразрядный 31-байтовый идентификатор с 31-байтовым ключом, суммирование полученных байтов, преобразование в десятичную и добавление цифр вместе до тех пор, пока оно не станет меньше 62, затем сопоставление его с символом в наборе [a-bA-Z0-9] (псевдокод ниже). Проблема в том, что, хотя я уверен, что это не отменит никаких действительных запросов, я не уверен, как определить, как часто это будет проходить через недопустимые идентификаторы или если ключ можно получить с помощью конечного значения.

Set alphabet to (byte[]) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
Set keystring to "aLaklj14sdLK87kxcvalskj7asfrq01";

Create empty byte[] key;
FOR each letter in keystring
  Push (index of letter in alphabet) to key;

Create empty byte[] step1;

FOR each (r, k) in (request, key)
  Push r XOR s to step1;

Set step2 to 0;
FOR each b in step1
  Add (int) b to step2;

WHILE step2 > 62
  Copy step2 to step3;
  Set step2 to 0;
  Convert step3 to String;
  Split step3 between characters;
  FOR each digit in step3
    Add (int) digit to step2;
END WHILE

RETURN alphabet[step2]

Официально

Детерминированная хеш-функция, где, учитывая закрытый ключ и вход длиной 31 байт, выводит результат в наборе {x | x ∈ ℕ, x < 62}, где угадание результата будет более эффективным, чем вычисление закрытого ключа. (Бонусные точки для ввода переменной длины)

В конечном итоге это будет реализовано в NodeJS/JavaScript, но на самом деле не зависит от языка.


Отказ от ответственности: Прошу прощения, если этот вопрос слишком расплывчатый и теоретический. Просьба прокомментировать, если это необходимо. Есть, очевидно, способы решения этой проблемы, но в этом случае я ищу как можно более эффективное решение.

4b9b3361

Ответ 1

Если вы хотите "детерминированную хеш-функцию" с закрытым ключом, то я считаю, что вы можете просто использовать sha256 (или любую другую хеш-функцию в вашей крипто-библиотеке) с добавленным ключом к вводу:

sha256(input+key).toString('hex');

Затем возьмите последние несколько бит хэш-значения, преобразуйте его из шестнадцатеричной строки в целое, разделите целое число на 62, получите остаток и определите символ на основе остатка.

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

Ответ 2

Один из подходов заключался бы в создании Blob URL, когда пользователь посещает начальный document. Blob URL должен быть уникальным для document, который создал URL. Затем пользователь может использовать Blob URL в качестве идентификатора запроса на сервере "B" . Когда пользователь делает запрос на "B" отменить Blob URL.

Blob URL уникален для каждого вызова URL.createObjectURL(), пользователь создает уникальный идентификатор, где время жизни Blob URL является временем жизни document, где создается Blob URL, или Blob URL отменяется. Существует минимальная возможность копирования Blob URL из браузера посетителей любым человеком, кроме пользователя, создавшего Blob URL, если только другие проблемы не существуют на компьютере пользователя.

const requestA = async() => {
  const blob = new Blob();
  const blobURL = URL.createObjectURL(blob);
  const A = await fetch("/path/to/server/A", {
              method:"POST", body:JSON.stringify({id:blobURL})
            });
  const responseA = await A.text(); 
  // do stuff with response
  return [blobURL, responseA];
}

Сервер "A" связывает созданные Blob URL с сервером "B"

const requestB = async(blobURL) => {
  const blob = new Blob();
  const blobURL = URL.createObjectURL(blob);
  const B = await fetch("/path/to/server/B", {
              method:"POST", body:JSON.stringify({id:blobURL})
            });
  const responseB = await B.text(); 
  return responseB
}

requestA()
.then(([blobURL, responseA] => {
  // do stuff with `responseA`
  console.log(responseA);
  // return `requestB` with `blobURL` as parameter
  return requestB(blobURL)
})
.then(responseB => console.log(responseB) // do stuff with `responseB`)
.catch(err => console.error(err));