我的团队交出了一些服务器端代码(在Java中),生成随机令牌,我有一个关于相同的问题
这些令牌的用途相当敏感——用于会话id、密码重置链接等。所以它们确实需要加密随机,以避免有人猜测它们或强行使用它们。令牌是一个“长”,所以它是64位长。
代码目前使用java.util.Random类来生成这些令牌。java.util.Random的文档清楚地说明了以下内容:
java.util.Random的实例不是加密安全的。相反,可以考虑使用securerrandom来获得一个加密安全的伪随机数生成器,以供对安全敏感的应用程序使用。
然而,代码目前使用java.util.Random的方式是这样的——它实例化java.security. securerrandom类,然后使用securerrandom . nextlong()方法来获得用于实例化java.util.Randomclass的种子。然后它使用java.util.Random.nextLong()方法生成令牌。
所以我现在的问题是——考虑到java.util.Random是使用java.security.SecureRandom进行播种的,它仍然是不安全的吗?我是否需要修改代码,以便它专门使用java.security. securerrandom来生成令牌?
目前,代码种子在启动时是随机的
java.util.Random.nextLong()的当前参考实现对next(int)方法进行了两次调用,该方法直接公开了当前种子的32位:
protected int next(int bits) {
long nextseed;
// calculate next seed: ...
// and store it in the private "seed" field.
return (int)(nextseed >>> (48 - bits));
}
public long nextLong() {
// it's okay that the bottom word remains signed.
return ((long)(next(32)) << 32) + next(32);
}
nextLong()结果的前32位是当时种子的位。因为种子的宽度是48位(javadoc说),所以它足以*遍历剩下的16位(也就是只有65.536次尝试)来确定产生第二个32位的种子。
一旦知道了种子,就可以很容易地计算所有后续令牌。
直接使用nextLong()的输出,部分地计算PNG的秘密,从而可以很轻松地计算出整个秘密。危险!
*如果第二个32位是负的,需要一些努力,但人们可以发现这一点。
java.util.Random.nextLong()的当前参考实现对next(int)方法进行了两次调用,该方法直接公开了当前种子的32位:
protected int next(int bits) {
long nextseed;
// calculate next seed: ...
// and store it in the private "seed" field.
return (int)(nextseed >>> (48 - bits));
}
public long nextLong() {
// it's okay that the bottom word remains signed.
return ((long)(next(32)) << 32) + next(32);
}
nextLong()结果的前32位是当时种子的位。因为种子的宽度是48位(javadoc说),所以它足以*遍历剩下的16位(也就是只有65.536次尝试)来确定产生第二个32位的种子。
一旦知道了种子,就可以很容易地计算所有后续令牌。
直接使用nextLong()的输出,部分地计算PNG的秘密,从而可以很轻松地计算出整个秘密。危险!
*如果第二个32位是负的,需要一些努力,但人们可以发现这一点。