Search code examples
javasecuritypromotion-code

Generate range of promotion codes that are not guessable


I'm looking for a way to generate a range of promotion codes. It would be trivial if it wasn't for both these requirements. That it needs to be a range (not saving every single promotion code in a database) to make it fast and that it is not guessable so it can not generate codes like this 000-000-001, 000-000-002, 000-000-003... and so on.

Is there an algorithm to solve this problem? I could try to solve it with some sort of hashing but trying to solve this security problem myself might leave the service open to exploits that I didn't think about.


Solution

  • I think your first requirement (not saving every promotional code in a database) is problematic.

    The question is, is it allowed to redeem a single promotional code multiple times?

    If this is not allowed then you have to store the already redeemed codes in some persistent data store anyway, so why not store the generated codes in the persistent data store from the beginning, together with a flag indicating whether it has been redeemed or not?


    If you don't want to store all codes / can't store all codes, you could still use a Random with a seed unique to your current campaign:

    long seed = 20190921065347L; // identifies your current campaign
    Random r = new Random(seed);
    for (int i = 0; i < numCodes; i++) {
        System.out.println(r.nextLong());
    }
    

    or

    long seed = 20190921065347L; // identifies your current campaign
    Random r = new Random(seed);
    r.longs(numCodes, 100_000_000_000_000L, 1_000_000_000_000_000L)
     .forEach(System.out::println);
    

    To find out whether a code is valid you can generate the same codes again:

    long seed = 20190921065347L; // identifies your current campaign
    Random r = new Random(seed);
    System.out.println(
        r.longs(numCodes, 100_000_000_000_000L, 1_000_000_000_000_000L)
         .anyMatch(l -> l == 350160558695557L));