Просмотр исходного кода

Use secure RNG to generate passwords (#2726)

* use secure rng to generate passwords

quoting MDN:
>Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead

My rng is kinda shitty, i know there is some fast way to cut down higher digits to get a digit in range without introducing bias, but i also know that other people have introduced bias by trying to do that on an initially secure rng and getting it wrong (iirc it's discussed here? https://www.youtube.com/watch?v=LDPMpc-ENqY - been years since i saw the talk, but i know Lavavej discussed it in one of his presentations, i think it was that one)  , but anyway this is fast enough, and secure.

* shorter name

* randomString2 / centralize js string generation

* missed 2
divinity76 3 лет назад
Родитель
Сommit
365dab5670

+ 61 - 0
web/js/init.js

@@ -615,3 +615,64 @@ $(document).ready(function(){
             });
     });
 
+/**
+ * generates a random string
+ * using a cryptographically secure rng, 
+ * and ensuring it contains at least 1 lowercase, 1 uppercase, and 1 number.
+ * 
+ * @param int length 
+ * @throws Error if length is too small to create a "sufficiently secure" string
+ * @returns string
+ */
+function randomString2(length = 16) {
+  var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
+  var secure_rng = function (min, max) {
+    if (min < 0 || min > 0xffff) {
+      throw new Error(
+        "minimum supported number is 0, this generator can only make numbers between 0-65535 inclusive."
+      );
+    }
+    if (max > 0xffff || max < 0) {
+      throw new Error(
+        "max supported number is 65535, this generator can only make numbers between 0-65535 inclusive."
+      );
+    }
+    if (min > max) {
+      throw new Error("dude min>max wtf");
+    }
+    // micro-optimization
+    let randArr = max > 255 ? new Uint16Array(1) : new Uint8Array(1);
+    let ret;
+    let attempts = 0;
+    for (;;) {
+      crypto.getRandomValues(randArr);
+      ret = randArr[0];
+      if (ret >= min && ret <= max) {
+        return ret;
+      }
+      ++attempts;
+      if (attempts > 1000000) {
+        // should basically never happen with max 0xFFFF/Uint16Array.
+        throw new Error("tried a million times, something is wrong");
+      }
+    }
+  };
+  let attempts = 0;
+  let minimumStrengthRegex = new RegExp(
+    /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/
+  );
+  let randmax = chars.length - 1;
+  for (;;) {
+    let ret = "";
+    for (let i = 0; i < length; ++i) {
+      ret += chars[secure_rng(0, randmax)];
+    }
+    if (minimumStrengthRegex.test(ret)) {
+      return ret;
+    }
+    ++attempts;
+    if (attempts > 1000000) {
+      throw new Error("tried a million times, something is wrong");
+    }
+  }
+};

+ 2 - 14
web/js/pages/add_db.js

@@ -88,19 +88,7 @@ App.Listeners.DB.keypress_v_password();
 App.Listeners.DB.keypress_db_username();
 App.Listeners.DB.keypress_db_databasename();
 
-randomString = function(min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
-        $('input[name=v_password]').val(randomstring);
+randomString = function(min_length = 16) {    
+        $('input[name=v_password]').val(randomString2(min_length));
         App.Actions.DB.update_v_password();
-    }    
 }

+ 2 - 14
web/js/pages/add_mail_acc.js

@@ -115,26 +115,14 @@ App.Listeners.MAIL_ACC.keypress_v_password();
 
 
 randomString = function(min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
+    var randomstring = randomString2(min_length);
         $('input[name=v_password]').val(randomstring);
         if($('input[name=v_password]').attr('type') == 'text')
             $('#v_password').text(randomstring);
         else
-            $('#v_password').text(Array(randomstring.length+1).join('*'));
-        
+            $('#v_password').text(Array(randomstring.length+1).join('*'));s        
         App.Actions.MAIL_ACC.update_v_password();
         generate_mail_credentials();
-    }    
 }
 
 generate_mail_credentials = function() {

+ 4 - 16
web/js/pages/add_user.js

@@ -14,22 +14,10 @@ $(function() {
 });
 
 
-randomString = function(min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
-        $('input[name=v_password]').val(randomstring);
-        App.Actions.WEB.update_v_password();
-    }    
-}
+randomString = function (min_length = 16) {
+    $("input[name=v_password]").val(randomString2(min_length));
+    App.Actions.WEB.update_v_password();
+};
 
 App.Actions.WEB.update_v_password = function (){
     var password = $('input[name="v_password"]').val();

+ 2 - 15
web/js/pages/add_web.js

@@ -237,24 +237,11 @@ $(function() {
 
 
 function WEBrandom() {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = 16;
-    var webrandom = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        webrandom += chars.substr(rnum, 1);
-    }
-        document.v_add_web.v_stats_password.value = webrandom;
+        document.v_add_web.v_stats_password.value = randomString2(16);
 }
 
 function FTPrandom(elm) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = 16;
-    var ftprandomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        ftprandomstring += chars.substr(rnum, 1);
-    }
+    var ftprandomstring = randomString2(16);
     $(elm).parents('.ftptable').find('.v-ftp-user-psw').val(ftprandomstring);
 }
 

+ 2 - 14
web/js/pages/edit_db.js

@@ -94,20 +94,8 @@ App.Listeners.DB.keypress_db_databasename();
 
 
 randomString = function(min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
-        $('input[name=v_password]').val(randomstring);
-        App.Actions.DB.update_v_password();
-    }    
+    $('input[name=v_password]').val(randomString2(min_length));
+    App.Actions.DB.update_v_password();
 }
 
      

+ 11 - 22
web/js/pages/edit_mail_acc.js

@@ -93,28 +93,17 @@ $('#v_blackhole').on('click', function(evt){
 App.Listeners.MAIL_ACC.keypress_v_password();
 
 
-randomString = function(min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
-        $('input[name=v_password]').val(randomstring);
-        if($('input[name=v_password]').attr('type') == 'text')
-            $('#v_password').text(randomstring);
-        else
-            $('#v_password').text(Array(randomstring.length+1).join('*'));
-        
-        App.Actions.MAIL_ACC.update_v_password();
-        generate_mail_credentials();
-    }    
-}
+randomString = function (min_length = 16) {
+  var randomstring = randomString2(min_length);
+  $("input[name=v_password]").val(randomstring);
+  if ($("input[name=v_password]").attr("type") == "text")
+    $("#v_password").text(randomstring);
+  else 
+    $("#v_password").text(Array(randomstring.length + 1).join("*"));
+  App.Actions.MAIL_ACC.update_v_password();
+  generate_mail_credentials();
+};
+
 generate_mail_credentials = function() {
     var div = $('.mail-infoblock').clone();
     div.find('#mail_configuration').remove();

+ 1 - 13
web/js/pages/edit_user.js

@@ -1,18 +1,6 @@
 randomString = function(min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
-        $('input[name=v_password]').val(randomstring);
+        $('input[name=v_password]').val(randomString2(min_length));
         App.Actions.WEB.update_v_password();
-    }    
 }
 
 App.Actions.WEB.update_v_password = function (){

+ 2 - 17
web/js/pages/edit_web.js

@@ -276,26 +276,11 @@ $(function() {
 });
 
 function WEBrandom() {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = 16;
-    var webrandom = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        webrandom += chars.substr(rnum, 1);
-    }
-    document.v_edit_web.v_stats_password.value = webrandom;
+    document.v_edit_web.v_stats_password.value = randomString2(16);
 }
 
 function FTPrandom(elm) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = 16;
-    var ftprandomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        ftprandomstring += chars.substr(rnum, 1);
-    }
-
-    $(elm).parents('.ftptable').find('.v-ftp-user-psw').val(ftprandomstring);
+    $(elm).parents('.ftptable').find('.v-ftp-user-psw').val(randomString2(16));
     App.Actions.WEB.randomPasswordGenerated && App.Actions.WEB.randomPasswordGenerated(elm);
 }
 

+ 2 - 14
web/js/pages/setup_webapp.js

@@ -1,16 +1,4 @@
 randomString = function(target, min_length = 16) {
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
-    var string_length = min_length;
-    var randomstring = '';
-    for (var i = 0; i < string_length; i++) {
-        var rnum = Math.floor(Math.random() * chars.length);
-        randomstring += chars.substr(rnum, 1);
-    }
-    var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
-    if(!regex.test(randomstring)){
-        randomString();
-    }else{
-        elm = document.getElementById(target);
-        $(elm).val(randomstring);
-    }    
+    elm = document.getElementById(target);
+    $(elm).val(randomString2(min_length));
 }