Как сгенерировать проверочный код / ​​номер?

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

Я хотел бы иметь возможность определить, правильный ли номер, который они вводят, или нет. Телефонная система не имеет доступа к списку действительных номеров, но вместо этого она проверяет номер на соответствие алгоритму (например, номеру кредитной карты).

Вот некоторые из требований:

  • Должно быть сложно ввести действительный случайный код
  • Должно быть сложно получить действительный код, если я сделаю опечатку (перестановка цифр, неправильная цифра)
  • У меня должно быть разумное количество возможных комбинаций (скажем, 1M)
  • Код должен быть как можно короче, чтобы не допустить ошибок со стороны пользователя.

Как бы вы сгенерировали такое число, учитывая эти требования?

РЕДАКТИРОВАТЬ :

@Haaked: код должен быть числовым, потому что пользователь набирает его на своем телефоне.

@matt b: на первом этапе код отображается на веб-странице, на втором этапе необходимо вызвать и ввести код. Я не знаю телефонного номера пользователя.

Продолжение: я нашел несколько алгоритмов проверить для проверки действительности чисел (см. Этот интересный проект Google Code: checkDigits).

Алгоритм в телефоне можно легко реконструировать. Поэтому его нельзя использовать в качестве меры по борьбе с мошенничеством или спамом.

Siavoshkc 03.02.2019 21:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
27
1
46 005
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Для 1M комбинаций вам понадобится 6 цифр. Чтобы убедиться, что нет никаких случайно действительных кодов, я предлагаю 9 цифр с вероятностью 1/1000, что случайный код работает. Я также предлагаю использовать другую цифру (всего 10) для выполнения проверка целостности. Что касается шаблонов распределения, случайного будет достаточно, а контрольная цифра гарантирует, что единственная ошибка не приведет к правильному коду.

Редактировать: Видимо я не полностью прочитал ваш запрос. Используя номер кредитной карты, вы можете выполнить хеширование (MD5 или SHA1 или что-то подобное). Затем вы обрезаете в соответствующем месте (например, 9 символов) и конвертируете в основание 10. Затем вы добавляете контрольную цифру (а), и это должно более или менее работать для ваших целей.

  • I must have a reasonnable number of possible combinations (let's say 1M)
  • The code must be as short as possible, to avoid errors from the user

Что ж, если вы хотите, чтобы в нем был хотя бы один миллион комбинаций, вам нужно как минимум шесть цифр. Достаточно ли коротко?

У вас есть доступ к номеру телефона звонящего при создании кода подтверждения?

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

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

Конечно, это не сработает, если номер телефона, использованный на шаге 1, отличается от того, с которого они звонят на шаге 2.

Это должны быть только цифры? Вы можете создать случайное число от 1 до 1M (я бы предложил даже больше), а затем Base32 кодирует это. Следующее, что вам нужно сделать, это хешировать это значение (используя секретное значение соли) и base32 закодировать хеш. Затем соедините две строки вместе, возможно, разделив их тире.

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

Предполагая, что вы уже знаете, как определить, какой ключ нажимает пользователь, это должно быть достаточно легко выполнимо. В мире безопасности существует понятие «одноразового» пароля. Иногда это называют «одноразовым паролем». Обычно они ограничиваются (легко вводимыми) значениями ASCII. Итак, [a-zA-z0-9] и куча легко вводимых символов. например запятая, точка, точка с запятой и круглые скобки. Однако в вашем случае вы, вероятно, захотите ограничить диапазон до [0-9] и, возможно, включить * и #.

Я не могу объяснить все технические детали того, как эти одноразовые коды генерируются (или работают) должным образом. За этим стоит некоторая промежуточная математика, которую я бы разделал, не просматривая ее сначала. Достаточно сказать, что вы используете алгоритм для генерации потока одноразовых паролей. Сколько бы вы ни знали предыдущих кодов, угадать последующий будет невозможно! В вашем случае вы просто будете использовать каждый пароль в списке как случайный код пользователя.

Вместо того, чтобы самому объяснять детали реализации, я направлю вас к статье на 9 страницах, где вы можете прочитать об этом сами: https://www.grc.com/ppp.htm

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

В прошлом люди делали это несколькими способами.

  1. Сделайте открытый ключ и закрытый ключ. Закодируйте числа 0-999,999 с помощью закрытого ключа и раздайте результаты. Вам нужно будет добавить несколько случайных чисел, чтобы результат перешел в более длинную версию, и вам нужно будет преобразовать результат из базы 64 в базу 10. Когда вы введете число, преобразуйте его обратно в base64, примените закрытый ключ и посмотрите, не меньше ли интересующие числа 1 000 000 (отбросьте случайные числа).
  2. Используйте обратимая хеш-функция
  3. Используйте первый миллион чисел из PRN с определенным значением. Функция "проверки" может получить начальное число и знать, что следующий миллион значений хорош. Он может либо генерировать их каждый раз и проверять одно за другим при получении кода, либо при запуске программы сохранять их все в таблице, сортировать, а затем использовать двоичный поиск (максимум сравнений), поскольку один миллион целых чисел - это не так много пространства.

Есть множество других вариантов, но они распространены и их легко реализовать.

-Адам

Вы связались с проектом проверить цифры, и использование функции "encode" кажется хорошим решением. Он говорит:

encode may throw an exception if 'bad' data (e.g. non-numeric) is passed to it, while verify only returns true or false. The idea here is that encode normally gets it's data from 'trusted' internal sources (a database key for instance), so it should be pretty usual, in fact, exceptional that bad data is being passed in.

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

Ответ принят как подходящий

После некоторого исследования, думаю, я воспользуюсь формулой ISO 7064 Мод 97,10. Это кажется довольно надежным, поскольку он используется для проверки IBAN (международного номера банковского счета).

Формула очень проста:

  1. Возьмите число: 123456
  2. Примените следующую формулу, чтобы получить 2-значную контрольную сумму: mod(98 - mod(number * 100, 97), 97) => 76
  3. Число Concat и контрольная сумма для получения кода => 12345676
  4. Чтобы проверить код, убедитесь, что mod(code, 97) == 1

Тест :

  • mod(12345676, 97) = 1 => ХОРОШО
  • mod(21345676, 97) = 50 => ПЛОХО!
  • mod(12345678, 97) = 10 => ПЛОХО!

Судя по всему, этот алгоритм вылавливает большинство ошибок.

Еще один интересный вариант - Алгоритм Верхоффа. Он имеет только одну контрольную цифру и его сложнее реализовать (по сравнению с простой формулой, приведенной выше).

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

Nick Johnson 09.07.2009 16:42

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

Costo 14.07.2009 04:10

При вычислении контрольной суммы с длиной, подобной IBAN, имейте в виду, что промежуточная сумма часто не помещается в 32-битное целое число со знаком.

AndreKR 05.07.2011 02:17

checksum может состоять из 1 цифры. Итак, в этом случае вы должны префикс cero. например для 256 код будет 25609. не путайте с 2569

Jaider 12.10.2013 00:23

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

Sprague 12.10.2016 12:57

@Sprague OP спросил о «проверочном коде», что означает для меня, что они не хотят, чтобы пользователи могли придумать его, не получив его.

Nick Johnson 12.10.2016 19:07

Я нашел эту ссылку с алгоритмом Верхоффа en.wikibooks.org/wiki/Algorithm_Implementation/Checksums/…

Ricardo da Rocha Vitor 30.06.2017 18:11

Вы хотите сегментировать свой код. Часть его должна быть 16-битной CRC остальной части кода.

Если вам нужен только проверочный номер, просто используйте порядковый номер (при условии, что у вас есть единственная точка генерации). Таким образом, вы будете знать, что не получите дубликатов.

Затем вы добавляете к последовательности префикс CRC-16 этого порядкового номера И некоторого закрытого ключа. Вы можете использовать что угодно в качестве закрытого ключа, если вы сохраняете его конфиденциальность. Сделайте что-нибудь большое, по крайней мере, GUID, но это может быть текст Война и мир из проекта Gutenberg. Просто нужно быть тайным и постоянным. Наличие закрытого ключа не позволяет людям подделать ключ, но использование 16-битного CR упрощает взлом.

Для проверки вы просто разделите номер на две части, а затем возьмете CRC-16 порядкового номера и закрытого ключа.

Если вы хотите больше скрыть последовательную часть, разделите CRC на две части. Поместите 3 цифры в начале и 2 в конце последовательности (заполните нулями, чтобы длина CRC была согласованной).

Этот метод позволяет вам также начать с меньших ключей. Первые 10 ключей будут 6-значными.

Другие вопросы по теме