web-dev-qa-db-fra.com

Sécuriser des nombres aléatoires en javascript?

Comment générer des nombres aléatoires cryptographiquement sécurisés en javascript?

75
Kyle

Vous pouvez par exemple utiliser le mouvement de la souris comme graine pour des nombres aléatoires, lire l'heure et la position de la souris à chaque fois que l'événement onmousemove se produit, alimenter ces données en fonction de blanchiment et vous aurez une première classe aléatoire à portée de main. Assurez-vous cependant que l'utilisateur a suffisamment déplacé la souris avant d'utiliser les données.

Edit: J'ai moi-même joué un peu avec le concept en créant un générateur de mot de passe, je ne garantirais pas que ma fonction de blanchiment est sans défaut, mais étant constamment réensemencée, je suis presque sûr que c'est suffisant pour le travail: ebusiness.hopto.org /generator.htm

Edit2: Cela fonctionne désormais avec les smartphones, mais uniquement en désactivant la fonctionnalité tactile pendant que l'entropie est collectée. Android ne fonctionnera pas correctement d'une autre manière.

23
aaaaaaaaaaaa

Il y a eu une discussion au WHATWG sur l'ajout de cela à l'objet window.crypto. Vous pouvez lire la discussion et consulter le API proposée et le bogue webkit (22049).

Je viens de tester le code suivant dans Chrome pour obtenir un octet aléatoire:

(function(){
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  alert(buf[0]);
})();
58
Paul V

Dans l'ordre, je pense que vos meilleurs paris sont:

  1. window.crypto.getRandomValues ​​ou window.msCrypto.getRandomValues
  2. Fonction randomWords de la bibliothèque sjcl ( http://crypto.stanford.edu/sjcl/ )
  3. Le générateur de nombres aléatoires de la bibliothèque isaac (qui est semé par Math.random, donc pas vraiment sécurisé cryptographiquement) ( https://github.com/rubycon/isaac.js )

window.crypto.getRandomValues ​​a été implémenté dans Chrome pendant un certain temps maintenant, et relativement récemment dans Firefox également. Malheureusement, Internet Explorer 10 et versions antérieures n'implémente pas la fonction. IE 11 a window.msCrypto, qui accomplit la même chose. Sjcl a un grand générateur de nombres aléatoires issu des mouvements de la souris, mais il y a toujours une chance que la souris ne se soit pas déplacée suffisamment pour amorcer le générateur, ou que l'utilisateur se trouve sur un appareil mobile où il n'y a aucun mouvement de la souris. Par conséquent, je recommande d'avoir un cas de secours où vous pouvez toujours obtenir un numéro aléatoire non sécurisé s'il n'y a pas le choix. Voici comment j'ai géré cela:

function GetRandomWords (wordCount) {
    var randomWords;

    // First we're going to try to use a built-in CSPRNG
    if (window.crypto && window.crypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.crypto.getRandomValues(randomWords);
    }
    // Because of course IE calls it msCrypto instead of being standard
    else if (window.msCrypto && window.msCrypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.msCrypto.getRandomValues(randomWords);
    }
    // So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
    // sjcl might help us out here
    else if (sjcl.random.isReady()) {
        randomWords = sjcl.random.randomWords(wordCount);
    }
    // Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
    // so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
    // have to make to crack the password.
    else {
        randomWords = [];
        for (var i = 0; i < wordCount; i++) {
            randomWords.Push(isaac.Rand());
        }
    }

    return randomWords;
};

Vous devrez inclure sjcl.js et isaac.js pour cette implémentation, et assurez-vous de démarrer le collecteur d'entropie sjcl dès que votre page est chargée:

sjcl.random.startCollectors();

sjcl est BSD et GPL sous double licence, tandis que isaac.js est MIT, il est donc parfaitement sûr d'utiliser l'un ou l'autre dans n'importe quel projet. Comme mentionné dans une autre réponse, clipperz est une autre option, mais pour une raison bizarre, il est sous licence AGPL. Je n'ai encore vu personne qui semble comprendre quelles implications cela a pour une bibliothèque JavaScript, mais je l'éviterais universellement.

Une façon d'améliorer le code que j'ai publié pourrait être de stocker l'état du générateur de nombres aléatoires isaac dans localStorage, afin qu'il ne soit pas réamorcé chaque fois que la page est chargée. Isaac va générer une séquence aléatoire, mais à des fins de cryptographie, la graine est primordiale. L'ensemencement avec Math.random est mauvais, mais au moins un peu moins mauvais s'il n'est pas nécessairement à chaque chargement de page.

27
ZeroG

Utilisez window.crypto.getRandomValues , comme ceci:

var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits
window.crypto.getRandomValues(random_num);

Ceci est pris en charge dans tous les navigateurs modernes et utilise le générateur aléatoire du système d'exploitation (par exemple /dev/urandom ). Si vous avez besoin de la compatibilité IE11, vous devez cependant utiliser leur implémentation préfixée viavar crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..).

Notez que l'API window.crypto Peut également générer directement des clés , ce qui peut être la meilleure option.

11
phihag

Vous voudrez peut-être essayer http://sourceforge.net/projects/clipperzlib/ Il a une implémentation de Fortuna qui est un générateur de nombres aléatoires cryptographiquement sécurisé. (Jetez un œil à src/js/Clipperz/Crypto/PRNG.js). Il semble également utiliser la souris comme source de hasard.

4
ameer

pour obtenir un nombre fort cryptographique à partir de la plage [0, 1) (similaire à Math.random()) utilisez crypto :

let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

console.log( random() );
4
Kamil Kiełczewski

Tout d'abord, vous avez besoin d'une source d'entropie. Par exemple, mouvement de la souris, du mot de passe ou de tout autre. Mais toutes ces sources sont très loin d'être aléatoires et vous garantissent 20 entropies, rarement plus. La prochaine étape que vous devez prendre consiste à utiliser le mécanisme comme "KDF basé sur mot de passe", il sera difficile sur le plan informatique de distinguer les données des données aléatoires.

1
user2674414