O tópico SecureRandom é seguro?

103

O SecureRandomtópico é seguro? Ou seja, após inicializá-lo, o acesso ao próximo número aleatório pode ser considerado seguro para threads? Examinar o código-fonte parece mostrar que sim, e este relatório de bug parece indicar que a falta de documentação como thread-safe é um problema do javadoc. Alguém confirmou que é de fato thread-safe?

Yishai
fonte

Respostas:

108

Sim, ele é. Ele estende Random, que sempre teve uma implementação threadsafe de fato , e, de Java 7, garante explicitamente a threadsafe.

Se muitos encadeamentos estiverem usando um único SecureRandom, pode haver contenção que prejudica o desempenho. Por outro lado, inicializar uma SecureRandominstância pode ser relativamente lento. Se é melhor compartilhar um RNG global ou criar um novo para cada thread dependerá de sua aplicação. A ThreadLocalRandomclasse pode ser usada como um padrão para fornecer uma solução compatível SecureRandom.

Erickson
fonte
3
Obrigado pela atualização. Estranhamente, o bug está marcado como "não corrige". Mas eles consertaram de qualquer maneira. Bem, não os invejo pelo tamanho de seu banco de dados de bugs.
Yishai,
4
a inicialização de um SecureRandompode não apenas ser lenta, mas pode travar devido à falta de entropia
Walter Tross
8
Lembre-se de que ThreadLocalRandom é muito fácil de quebrar, então se você planeja expor o valor gerado para o mundo, use SecureRandom em vez de jazzy.id.au/default/2010/09/20/…
walv
2
Vou me arriscar aqui e dizer que a resposta está incorreta. O contrato para Random, que garante a segurança do thread, não é vinculativo às subclasses. Certamente todas as outras propriedades de Random documentadas não são vinculativas em subclasses, então não vejo por que thread-safety deve ser assumido.
Presidente James K. Polk
2
@JamesKPolk A falha em preservar uma propriedade do supertipo violaria o princípio da substituibilidade.
Erickson
11

A implementação atual do SecureRandomé thread-safe, especificamente os dois métodos mutantes nextBytes(bytes[])e setSeed(byte[])são sincronizados.

Bem, pelo que pude perceber, todos os métodos mutantes são eventualmente roteados por meio desses dois métodos e SecureRandomsubstituem alguns métodos Randompara garantir isso. Que funciona, mas pode ser frágil se a implementação for alterada no futuro.

A melhor solução é sincronizar manualmente na SecureRandominstância primeiro. Isso significa que cada pilha de chamadas adquirirá dois bloqueios no mesmo objeto, mas isso geralmente é muito barato em JVMs modernos. Ou seja, não há muito mal em se sincronizar explicitamente. Por exemplo:

    SecureRandom rnd = ...;

    byte[] b = new byte[NRANDOM_BYTES];
    synchronized (rnd) {
        rnd.nextBytes(b);
    }
Matt Quail
fonte
3
Pelo menos no JDK 10, SecureRandom é baseado em um provedor e verifica se o provedor é seguro para thread, apenas sincronizando se não for, em nextBytes.
nafg de
java.security.SecureRandom#nextBytesno Java 8 não está sincronizado. Você poderia especificar em qual versão do Java você encontrou um sincronizado #nextBytes?
Jaime Hablutzel