|
| 1 | +# 如何产生一个随机的字母数字串作为 session 的唯一标识符? |
| 2 | + |
| 3 | +如果允许产生的随机字符串是可猜测的(随机字符串比较都短,或者使用有缺陷的随机数生成器),进而导致攻击者可能会劫持到会话的,可以使用一个相对简单随机数生成代码,如下所示: |
| 4 | +``` |
| 5 | +public class RandomString { |
| 6 | +
|
| 7 | + private static final char[] symbols; |
| 8 | +
|
| 9 | + static { |
| 10 | + StringBuilder tmp = new StringBuilder(); |
| 11 | + for (char ch = '0'; ch <= '9'; ++ch) |
| 12 | + tmp.append(ch); |
| 13 | + for (char ch = 'a'; ch <= 'z'; ++ch) |
| 14 | + tmp.append(ch); |
| 15 | + symbols = tmp.toString().toCharArray(); |
| 16 | + } |
| 17 | +
|
| 18 | + private final Random random = new Random(); |
| 19 | +
|
| 20 | + private final char[] buf; |
| 21 | +
|
| 22 | + public RandomString(int length) { |
| 23 | + if (length < 1) |
| 24 | + throw new IllegalArgumentException("length < 1: " + length); |
| 25 | + buf = new char[length]; |
| 26 | + } |
| 27 | +
|
| 28 | + public String nextString() { |
| 29 | + for (int idx = 0; idx < buf.length; ++idx) |
| 30 | + buf[idx] = symbols[random.nextInt(symbols.length)]; |
| 31 | + return new String(buf); |
| 32 | + } |
| 33 | +} |
| 34 | +``` |
| 35 | + |
| 36 | +为了安全,可以考虑使用下面这段简洁且安全的代码,不过用其作为 session 的标识符,倒显得有点大材小用了(比较耗时): |
| 37 | +``` |
| 38 | +import java.security.SecureRandom; |
| 39 | +
|
| 40 | +public final class SessionIdentifierGenerator { |
| 41 | + private SecureRandom random = new SecureRandom(); |
| 42 | +
|
| 43 | + public String nextSessionId() { |
| 44 | + return new BigInteger(130, random).toString(32); |
| 45 | + } |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +其工作原理就是,使用一个 130 位的安全的随机数生成器生成一个随机数,接着转化为 32 进制。我们知道,128 位安全随机数的生成已经是足够安全的,不过以 32 进制编码的每一个数字可编码 5 位,所以需要取大于 128 且是 5 的倍数,所以就选择了 130 位。相对于 随机 UUID 来说(在标准输出中,每个字符使用 3.4 bit,共 122 bit),每个字符使用 5 个随机的 bit 来编码的方式,显得更为简洁和高效。 |
| 50 | + |
| 51 | +译者注:上面两段代码,生成26位随机字符串,第一段代码每次耗时不到1ms,第二段耗时约100ms。也就是说第一段代码更快,但第二段代码更安全,但更耗时。 |
| 52 | + |
| 53 | +stackoverflow原链接: |
| 54 | +http://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string |
0 commit comments