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

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

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

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

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

Ответ 1

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

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

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

Ответ 2

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

Разрешимость: Неопровержимые числа

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

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

Разделите номер своего счета в двух частях:

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

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

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

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

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

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

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

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

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

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

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

Пример:

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

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

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

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

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

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

Ответ 3

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

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

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

11010101111000100101101100111101

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

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

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

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

  • ID
  • Двоичное представление 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

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

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

Чтобы покрыть его проблемы, вы можете зарезервировать последние, скажем, 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 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;

    }

}

Ответ 4

Возможно, идея может исходить из мельницы? групповые счета-фактуры в таких блоках:
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
группы не обязательно должны быть последовательными, но числа в группах выполняются

UPDATE

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

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

Ответ 5

Из приведенного ниже кода вы можете видеть, что я использую 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]; 

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

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

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

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

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

(201308141403) * 3 = 603924424209

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

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

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

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

Ответ 10

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

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

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);