0
点赞
收藏
分享

微信扫一扫

SecureRandom.getInstanceStrong引起的线程阻塞

凶猛的小白兔 2022-03-30 阅读 49
java

项目场景:

某个项目中,sonar扫描到使用Random随机函数不安全, 推荐使用SecureRandom替换,于是就换成了使用SecureRandom.getInstanceStrong()获取SecureRandom并调用nextInt()。

悲剧开始了...


问题描述

在生产环境(linux)产生较长时间的阻塞,造成了nginx返回大量499,一度以为是tomcat不接收消息或是nginx转发问题,但开发环境(windows10)并未重现。


原因分析:

通过jstack发现,有599个线程的状态为waiting for monitor entry,在等待一个对象,而拥有这个对象的线程又被阻塞。

可以看到该线程阻塞在了java.io.FileInputStream.readBytes(Native Method)这个读取文件的IO处。对NativePRNG的部分关键源码进行分析:

// name of the pure random file (also used for setSeed())
    private static final String NAME_RANDOM = "/dev/random";
    // name of the pseudo random file
    private static final String NAME_URANDOM = "/dev/urandom";

    private static RandomIO initIO(final Variant v) {
        return AccessController.doPrivileged(
                new PrivilegedAction<RandomIO>() {
                    @Override
                    public RandomIO run() {
                        File seedFile;
                        File nextFile;

                        switch(v) {
                            //...忽略中间代码
                            case BLOCKING: // blocking状态下从/dev/random文件中读取
                                seedFile = new File(NAME_RANDOM);
                                nextFile = new File(NAME_RANDOM);
                                break;

                            case NONBLOCKING: // unblocking状态下从/dev/urandom文件中读取数据
                                seedFile = new File(NAME_URANDOM);
                                nextFile = new File(NAME_URANDOM);
                                break;
                            //...忽略中间代码
                            try {
                                return new RandomIO(seedFile, nextFile);
                            } catch (Exception e) {
                                return null;
                            }
                        }
                    });
                }

       // constructor, called only once from initIO()
        private RandomIO(File seedFile, File nextFile) throws IOException {
            this.seedFile = seedFile;
            seedIn = new FileInputStream(seedFile);
            nextIn = new FileInputStream(nextFile);
            nextBuffer = new byte[BUFFER_SIZE];
        }

        private void ensureBufferValid() throws IOException {
            long time = System.currentTimeMillis();
            if ((buffered > 0) && (time - lastRead < MAX_BUFFER_TIME)) {
                return;
            }
            lastRead = time;
            readFully(nextIn, nextBuffer);
            buffered = nextBuffer.length;
        }

 从源代码分析,发现导致阻塞的原因是因为从/dev/random中读取随机数导致。

解决方案:

1. 可以通过修改环境配置解决:

打开$JAVA_PATH/jre/lib/security/java.security这个文件,找到下面的内容:

securerandom.source=file:/dev/random

替换成:

securerandom.source=file:/dev/./urandom

2. 修改代码:

不推荐使用SecureRandom.getInstanceStrong()方式获取SecureRandom(除非对随机要求很高)。

推荐使用new SecureRandom()获取SecureRandom,linux下从/dev/urandom读取。虽然是伪随机,但大部分场景下都满足。

参考:

SecureRandom.getInstanceStrong()引发的线程阻塞问题分析_磨唧的博客-CSDN博客_getinstancestrong

举报

相关推荐

0 条评论