问题

我一直在寻找asimpleJava算法来生成伪随机字母数字字符串。在我的情况下,它将被用作一个独特的会话/密钥标识符,“很可能”在50万代中是独一无二的(我的需求并不需要任何更复杂的东西)。理想情况下,我可以根据我的独特需要指定长度。例如,生成的长度为12的字符串可能看起来像“AEYGF7K0DM1X”。


#1 热门回答(1387 赞)

##算法

要生成一个随机字符串,将从可接受符号集合中随机抽取的字符连接起来,直到字符串达到所需的长度。

##执行

以下是一些非常简单且非常灵活的代码,用于生成随机标识符。阅读重要应用笔记中的信息。

import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;

public class RandomString {

    /**
     * Generate a random string.
     */
    public String nextString() {
        for (int idx = 0; idx < buf.length; ++idx)
            buf[idx] = symbols[random.nextInt(symbols.length)];
        return new String(buf);
    }

    public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static final String lower = upper.toLowerCase(Locale.ROOT);

    public static final String digits = "0123456789";

    public static final String alphanum = upper + lower + digits;

    private final Random random;

    private final char[] symbols;

    private final char[] buf;

    public RandomString(int length, Random random, String symbols) {
        if (length < 1) throw new IllegalArgumentException();
        if (symbols.length() < 2) throw new IllegalArgumentException();
        this.random = Objects.requireNonNull(random);
        this.symbols = symbols.toCharArray();
        this.buf = new char[length];
    }

    /**
     * Create an alphanumeric string generator.
     */
    public RandomString(int length, Random random) {
        this(length, random, alphanum);
    }

    /**
     * Create an alphanumeric strings from a secure generator.
     */
    public RandomString(int length) {
        this(length, new SecureRandom());
    }

    /**
     * Create session identifiers.
     */
    public RandomString() {
        this(21);
    }

}

##使用示例

为8个字符的标识符创建一个不安全的生成器:

RandomString gen = new RandomString(8, ThreadLocalRandom.current());

为会话标识符创建安全生成器:

RandomString session = new RandomString();

创建一个具有易于阅读的打印代码的生成器。字符串比完整的字母数字字符串长,以补偿使用更少的符号:

String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);

##用作会话标识符

生成可能是唯一的会话标识符不够好,或者您可以使用简单的计数器。当使用可预测的标识符时,攻击者劫持会话。

长度和安全之间存在紧张关系。较短的标识符更容易被猜出,因为可能性较少。但更长的标识符消耗更多的存储和带宽。更大的符号集有助于实现,但如果标识符包含在URL中或手动重新输入,可能会导致编码问题。

会话标识符的随机性或熵的基本来源应来自为密码学设计的随机数生成器。但是,初始化这些生成器有时可能在计算上很昂贵或很慢,所以应该尽可能地重复使用它们。

##用作对象标识符

并非每个应用程序都需要安全性随机分配可以是多个实体在共享空间中生成标识符的有效方式,无需任何协调或分区。协调可能会很慢,特别是在集群或分布式环境中,当实体最终分配太小或太大的份额时,分割空间会导致问题。

如果攻击者可能能够查看并操纵它们,那么在没有采取措施使其不可预知的情况下生成的标识符应该受到其他方式的保护,正如大多数Web应用程序中所发生的那样。应该有一个单独的授权系统,用于保护没有访问权限的攻击者可以猜出标识符的对象。

考虑到预期的标识符总数,还必须注意使用足够长的标识符以使碰撞不太可能。这被称为“生日悖论”。The probability of a collision,p大约是n2 /(2qx),其中n是实际生成的标识符的数量,q是字母表中不同符号的数量,x是标识符的长度。这应该是一个非常小的数字,比如2-50或更少。

解决这个问题表明,500k个15个字符的标识符之间相互碰撞的机会大约是2-52个,这可能比来自宇宙射线的未被发现的错误等更少。

##与UUID比较

根据它们的规范,UUID的设计不是不可预测的,并且不能用作会话标识符。

标准格式的UUID占用大量空间:只有122位熵的36个字符。 (并非随机选择“随机”UUID的所有位)随机选择的字母数字字符串仅包含21个字符的熵。

UUID不灵活;他们有一个标准化的结构和布局。这是他们的主要美德,也是他们的主要弱点。与外部团队合作时,UUID提供的标准化可能会有帮助。纯粹为了内部使用,它们可能效率低下。


#2 热门回答(726 赞)

Java提供了一种直接执行此操作的方法。如果你不想要破折号,他们很容易剥离。只需使用`uuid.replace(“ - ”,“”)``

import java.util.UUID;

public class randomStringGenerator {
    public static void main(String[] args) {
        System.out.println(generateString());
    }

    public static String generateString() {
        String uuid = UUID.randomUUID().toString();
        return "uuid = " + uuid;
    }
}

输出:

uuid = 2d7428a6-b58c-4008-8575-f05549f16316

#3 热门回答(463 赞)

static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();

String randomString( int len ){
   StringBuilder sb = new StringBuilder( len );
   for( int i = 0; i < len; i++ ) 
      sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
   return sb.toString();
}

原文链接