Идеи создания генерируемых идентификаторов Invoiceable Invoice ID

Я хочу распечатать счета для клиентов в своем приложении. Каждый счет-фактура имеет идентификатор счета- фактуры . Я хочу, чтобы идентификаторы были:

  • Последовательные (в последнее время ids задерживаются)
  • 32-битные целые числа
  • Нелегко проследить, как 1 2 3, чтобы люди не могли рассказать, сколько предметов мы продаем.

Моя идея: количество секунд с определенной даты и времени (например, 1/1/2010 00 AM).

Любые другие идеи, как генерировать эти числа?

Мне не нравится идея использовать время. Вы можете столкнуться со всеми проблемами – разница во времени, несколько событий, происходящих за одну секунду, и так далее.

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

Вы также можете добавить константу в свои идентификаторы, чтобы сделать их более впечатляющими. Например, вы можете добавить 44323 ко всем своим идентификаторам и повернуть идентификаторы 15, 23 и 27 в 44338, 44346 и 44350.

В вашем вопросе есть две проблемы. Один разрешимый, один – нет (с ограничениями, которые вы даете).

Разрешимость: неописуемые числа

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

Вы можете решить это с помощью своего ограничения:

Разделите номер счета-фактуры двумя частями:

  1. 20-битный префикс, взятый из последовательности возрастающих чисел (например, натуральных чисел 0,1,2, …)
  2. 10-битный суффикс, который генерируется случайным образом

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

Используйте последовательность SQL для передачи чисел. При выпуске нового (то есть неиспользованного) номера счета-фактуры увеличивайте seuqnce и выдавайте n-й номер из предварительно просчитанного списка (по порядку).

Не разрешимо: угадывание количества клиентов

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

У вас есть заявка на вариант, именуемый так называемой « проблемой немецкого танкера ». Во вторую мировую войну союзники использовали серийные номера, напечатанные на коробке передач немецких танков, для гостя, сколько танков было произведено в Германии. Это сработало, потому что серийный номер увеличивался без пробелов.

Но даже когда вы увеличиваете количество пробелов, решение проблемы с немецким танком все еще работает. Это довольно легко:

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

Теперь у вас есть хорошее предположение о порядке количества счетов-фактур (200, 15000, полмиллиона и т. Д.).

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

Существует встречная мера: вы должны убедиться, что не существует среднего значения для разрыва двух последовательных чисел. Генератор случайных чисел с этим свойством может быть построен очень просто.

Пример:

  1. Начните с последнего номера счета плюс один в качестве текущего номера
  2. Умножьте текущее число на случайное число> = 2. Это ваш новый текущий номер.
  3. Получите случайный бит: если бит равен 0, результатом будет ваш текущий номер. В противном случае вернитесь к шагу 2.

Хотя это будет работать теоретически, вы скоро закончите 32-битные целые числа.

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

Snakeoil (нерабочие решения)

Не используйте какое-либо временное решение. Временная метка обычно легко угадывается (вероятно, примерно правильная метка времени будет напечатана где-то в счете-фактуре). Использование временных меток обычно облегчает атаку, а не сложнее.

Не используйте незащищенные случайные числа. Большинство генераторов случайных чисел не являются криптографически безопасными. Они обычно имеют математические свойства, которые хороши для статистики, но плохие для вашей безопасности (например, предикативное распределение, стабильное среднее значение и т. Д.),

Одно решение может включать бинарные растровые изображения Exclusive OR (XOR). Функция результата обратима , может генерировать несекретные числа (если первый бит младшего значащего байта установлен в 1) и чрезвычайно прост в реализации. И, если вы используете надежный генератор последовательности (например, ваша база данных), нет необходимости в проблемах безопасности потоков.

Согласно MSDN , «результат [операции исключительного ИЛИ] является истинным тогда и только тогда, когда истинно один из его операндов». обратная логика говорит, что равные операнды всегда будут ошибочными.

В качестве примера я просто сгенерировал 32-битную последовательность на Random.org. Это оно:

11010101111000100101101100111101 

Это двоичное число преобразуется в 3588381501 в десятичном формате , 0xD5E25B3D в шестнадцатеричном формате . Назовем его базовым ключом .

Теперь давайте сгенерировать некоторые значения, используя формулу ([base key] XOR [ID]) . В C # это будет выглядеть ваша функция шифрования:

  public static long FlipMask(long baseKey, long ID) { return baseKey ^ ID; } 

Следующий список содержит некоторое сгенерированное содержимое. Его столбцы:

  • Я БЫ
  • Двоичное представление идентификатора
  • Двоичное значение после операции XOR
  • Финал, «зашифрованное» десятичное значение

     0 | 000 | 11010101111000100101101100111101 | 3588381501 1 | 001 | 11010101111000100101101100111100 | 3588381500 2 | 010 | 11010101111000100101101100111111 | 3588381503 3 | 011 | 11010101111000100101101100111110 | 3588381502 4 | 100 | 11010101111000100101101100111001 | 3588381497 

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

  11010101111000100101101100111101 XOR 11010101111000100101101100111100 = 00000000000000000000000000000001 

Это действительно ваша первоначальная ценность.

Теперь Стефан сделал очень хорошие очки, и первая тема имеет решающее значение.

Чтобы покрыть его проблемы, вы можете зарезервировать последние, скажем, 8 байтов, чтобы быть чисто случайным мусором (который, как мне кажется, называется nonce ), который вы создаете при шифровании исходного идентификатора и игнорируете при его обратном направлении. Это значительно увеличит вашу безопасность за счет щедрого кусочка всех возможных положительных целых чисел с 32 битами (16 777 216 вместо 4 294 967 296 или 1/256 из них).

Класс для этого будет выглядеть так:

 public static class int32crypto { // C# follows ECMA 334v4, so Integer Literals have only two possible forms - // decimal and hexadecimal. // Original key: 0b11010101111000100101101100111101 public static long baseKey = 0xD5E25B3D; public static long encrypt(long value) { // First we will extract from our baseKey the bits we'll actually use. // We do this with an AND mask, indicating the bits to extract. // Remember, we'll ignore the first 8. So the mask must look like this: // Significance mask: 0b00000000111111111111111111111111 long _sigMask = 0x00FFFFFF; // sigKey is our baseKey with only the indicated bits still true. long _sigKey = _sigMask & baseKey; // nonce generation. First security issue, since Random() // is time-based on its first iteration. But that's OK for the sake // of explanation, and safe for most circunstances. // The bits it will occupy are the first eight, like this: // OriginalNonce: 0b000000000000000000000000NNNNNNNN long _tempNonce = new Random().Next(255); // We now shift them to the last byte, like this: // finalNonce: 0bNNNNNNNN000000000000000000000000 _tempNonce = _tempNonce << 0x18; // And now we mix both Nonce and sigKey, 'poisoning' the original // key, like this: long _finalKey = _tempNonce | _sigKey; // Phew! Now we apply the final key to the value, and return // the encrypted value. return _finalKey ^ value; } public static long decrypt(long value) { // This is easier than encrypting. We will just ignore the bits // we know are used by our nonce. long _sigMask = 0x00FFFFFF; long _sigKey = _sigMask & baseKey; // We will do the same to the informed value: long _trueValue = _sigMask & value; // Now we decode and return the value: return _sigKey ^ _trueValue; } } 

может быть, идея может исходить от мельницы? групповые счета в таких блоках:
28-я стрелковая дивизия
– 1-я бригада
— 1-й BN
—- A Co
—- B Co
— 2-й BN
—- A Co
—- B Co
– 2-я бригада
— 1-й BN
—- A Co
—- B Co
— 2-й BN
—- A Co
—- B Co
– 3-я бригада
— 1-й BN
—- A Co
—- B Co
— 2-й BN
—- A Co
—- B Co
http://boards.straightdope.com/sdmb/showthread.php?t=432978
группы не обязательно должны быть последовательными, но номера в группах

ОБНОВИТЬ

Подумайте об этом выше, как группы, дифференцированные по месту, времени, человеку и т. Д. Например: создайте группу, используя временный идентификатор продавца, меняя его каждые 10 дней или в офисе или в магазине.

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

Из приведенного ниже кода вы можете видеть, что я использую newsequentialid () для генерации последовательного числа, а затем преобразую его в [bigint]. Поскольку это создает последовательное приращение 4294967296, я просто делю это число на [id] на таблице (это может быть rand (), засеянное наносекундами или что-то подобное). Результат – это число, которое всегда меньше 4294967296, поэтому я могу спокойно добавить его и быть уверенным, что я не перекрываю диапазон следующего числа.

Мир Кэтрин

 declare @generator as table ( [id] [bigint], [guid] [uniqueidentifier] default( newsequentialid()) not null, [converted] as (convert([bigint], convert ([varbinary](8), [guid], 1))) + 10000000000000000000, [converted_with_randomizer] as (convert([bigint], convert ([varbinary](8), [guid], 1))) + 10000000000000000000 + cast((4294967296 / [id]) as [bigint]) ); insert into @generator ([id]) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); select [id], [guid], [converted], [converted] - lag([converted], 1.0) over ( order by [id]) as [orderly_increment], [converted_with_randomizer], [converted_with_randomizer] - lag([converted_with_randomizer], 1.0) over ( order by [id]) as [disorderly_increment] from @generator order by [converted]; 

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

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

Если заказы сидят во вложенной папке, пока один человек не обрабатывает их каждое утро, увидев, что он взял этого человека до 16:00, прежде чем он обернется, чтобы создать мой счет, создается впечатление, что он занят. Получение счета 9:01 заставляет меня чувствовать, что я единственный клиент сегодня.

Но если вы создаете идентификатор в то время, когда я размещаю свой заказ, метка времени мне ничего не говорит.

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

Я думаю, что Na Na имеет правильную идею с выбором большого количества и подсчетами. Начните с большого значения семян и либо подсчитайте вверх или вниз, но не начинайте с последнего заполнителя. Если вы используете один из других заполнителей, это даст иллюзию более высокого счета-фактуры …. если они действительно смотрят на это в любом случае.

Единственное предостережение здесь состояло в том, чтобы периодически изменять последние цифры X числа, чтобы сохранить внешний вид изменения.

Почему бы не считать легко читаемый номер, построенный как

  • первые 12 цифр – это дата-время в формате yyyymmddhhmm (что гарантирует порядок ваших идентификаторов счета)
  • последние x-цифры – это номер заказа (в этом примере 8 цифр)

Число, которое вы получаете, это примерно как 20130814140300000008

Затем выполните некоторые простые вычисления с ним, как первые 12 цифр

 (201308141403) * 3 = 603924424209 

Вторая часть (оригинал: 00000008) может быть запутана следующим образом:

 (10001234 - 00000008 * 256) * (minutes + 2) = 49995930 

Его легко перевести обратно в легко читаемое число, но если вы не знаете, как клиент вообще не имеет понятия.

Все это число будет выглядеть как 603924424209-49995930 для счета-фактуры 14-го августа 2013 года в 14:03 с внутренним номером счета 00000008.

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

Пример генератора может быть

 private static string GetNextnumber(int currentNumber) { Int32 nextnumber = currentNumber + (currentNumber % 3) + 5; Random _random = new Random(); //you can skip the below 2 lines if you don't want alpha numeric int num = _random.Next(0, 26); // Zero to 25 char let = (char)('a' + num); return nextnumber + let.ToString(); } 

и вы можете позвонить как

 string nextnumber = GetNextnumber(yourpreviouslyGeneratedNumber);