สร้างรหัสผ่านแบบสุ่มใน php


190

ฉันกำลังพยายามสร้างรหัสผ่านแบบสุ่มใน php

อย่างไรก็ตามฉันได้รับทั้งหมดและชนิดกลับเป็นประเภท array และฉันต้องการให้เป็นสตริง ความคิดเห็นเกี่ยวกับวิธีการแก้ไขรหัส?

ขอบคุณ

function randomPassword() {
    $alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
    for ($i = 0; $i < 8; $i++) {
        $n = rand(0, count($alphabet)-1);
        $pass[$i] = $alphabet[$n];
    }
    return $pass;
}

9
ไม่มีคำตอบใดที่ใช้ตัวสร้างหมายเลขสุ่มที่ปลอดภัยซึ่งคุณต้องการรหัสผ่าน
Scott Arciszewski

4
ผู้เยี่ยมชมควรรับข้อมูลที่เกี่ยวข้องกับความปลอดภัยจากแหล่งที่สามารถอัปเดตได้อย่างถูกต้องไม่ใช่คำถามที่อยู่ใกล้กับคำตอบใหม่ ฉันกำลังลบคำตอบของคำซ้ำซ้อนเพื่อให้ผู้เข้าชมจะอ่านคำตอบของคำถามที่เปิดอยู่แทน (หากคำถามนี้ถูกเปิดใหม่อีกครั้งคำตอบจะถูกยกเลิกการลบ)
Jeremy Banks

6
@JeremyBanks ไม่มีคำถามใดที่ต้องระบุรหัสผ่านที่ปลอดภัยแบบเข้ารหัส สำหรับบางคนคำตอบที่ใช้/dev/randomนั้นเพียงพอสำหรับคำถามที่ไม่ขอรหัสผ่าน " ปลอดภัย " (และไม่ควรแก้ไขเพื่อให้มีรหัสเพราะจะเปลี่ยนความหมายของคำถามเดิม) แม้ว่าฉันจะปลอดภัย แต่ฉันคิดว่าพรมระเบิดนี้ยังไม่ได้คิดเต็มที่ เช่นเดียวกับการใช้mysql_*คำตอบยังใช้ได้ แต่ควรทำเครื่องหมายว่าไม่ปลอดภัย บางทีนี่อาจเป็นสิ่งที่ SO จำเป็นต้องรวมไว้เป็นซอฟต์แวร์พิเศษ - ความสามารถในการเตือนของรหัสที่ไม่ปลอดภัย?
Jimbo

6
@JeremyBanks คุณช่วยกรุณาคืนคำตอบสำหรับคำถามนี้ได้ไหม? เพียงเพราะมันซ้ำซ้อนมันไม่ได้หมายความว่าคำตอบนั้นผิด (ฉันตั้งใจโหวตให้เปิดใหม่อีกครั้งฉันยอมรับว่ามันซ้ำกัน) มันไม่มีเหตุผลที่จะลบคำตอบลองพิจารณานำคำถามนี้ออกและย้ายคำตอบไปยังคำถามอื่น (ฉันเคยเห็นมาก่อนแล้ว)
Naftali aka Neal

7
@ JeremyBanks ถ้าคุณต้องการที่จะไม่เปิดใหม่ให้ล็อคมัน มิฉะนั้นคน 99% จะเปิดใหม่อีกครั้งและสร้างความยุ่งเหยิงทั้งหมด โดยส่วนตัวแล้วฉันไม่เห็นด้วยกับการลบคำตอบที่ได้คะแนนสูง แต่ก็ไม่สามารถต่อสู้กับคุณได้
Shadow Wizard is Ear For You

คำตอบ:


258

คำเตือนด้านความปลอดภัย : rand()ไม่ใช่ตัวสร้างหมายเลขเทียมที่มีการเข้ารหัสลับที่ปลอดภัย ดูที่อื่น ๆ สำหรับการสร้างสตริง pseudorandom ที่เชื่อถือได้เข้ารหัสใน PHP

ลองใช้ (ใช้strlenแทนcountเพราะcountบนสตริงเป็นเสมอ1):

function randomPassword() {
    $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
    $pass = array(); //remember to declare $pass as an array
    $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
    for ($i = 0; $i < 8; $i++) {
        $n = rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
    return implode($pass); //turn the array into a string
}

การสาธิต: http://codepad.org/UL8k4aYK


24
ดูเหมือนว่าจะใช้ง่าย$pass .= $alphabet[$n]ขึ้น
Matthew

33
การสร้างรหัสผ่านโดยใช้แรนด์นั้นเป็นความคิดที่แย่จริงๆ มันไม่ใช่ PRNG ที่ปลอดภัย (และmt_randไม่ดีกว่าอย่างใดอย่างหนึ่ง)
CodesInChaos

19
คำถามที่เป็นเรื่องเกี่ยวกับการสร้างรหัสผ่าน รหัสเพื่อสร้างรหัสผ่านอย่างชัดเจนต้องใช้หมายเลขสุ่มที่ปลอดภัย
CodesInChaos

10
ด้วยเหตุผลเดียวกันเช่นนี้เป็นไม่ได้เป็นคำถามที่ซ้ำกันคำตอบนี้ไม่ถูกต้องตั้งแต่คำถามที่เป็นเรื่องเกี่ยวกับการสร้างรหัสผ่านและไม่สตริงแบบสุ่ม คำตอบนี้ให้วิธีการที่ไม่ปลอดภัยอย่างมากในการสร้างรหัสผ่าน โปรดใช้คำตอบของ @ user3260409 ด้านล่างซึ่งopenssl_random_pseudo_bytes()จะใช้แทนrand()
Sorry-Im-a-N00b

35
ฉันเห็นรหัสที่ไม่ปลอดภัยของคุณในการผลิตและต้องการหยุดมันที่แหล่งที่มา คุณต้องใช้รหัสผ่านแบบสุ่มที่ปลอดภัยสำหรับการเข้ารหัส
Scott Arciszewski

122

TL; DR:

  • ใช้งานrandom_int()และรับตามรายละเอียดrandom_str()ด้านล่าง
  • หากคุณไม่ได้มีrandom_int()การใช้random_compat

คำอธิบาย:

เมื่อคุณสร้างรหัสผ่านที่คุณต้องให้แน่ใจว่ารหัสผ่านที่คุณสร้างคาดเดาไม่ได้และวิธีเดียวที่จะให้สถานที่ให้บริการนี้มีอยู่ในการดำเนินงานของคุณคือการใช้เครื่องกำเนิดไฟฟ้าจำนวน pseudorandom ที่เชื่อถือได้เข้ารหัส (CSPRNG)

ข้อกำหนดสำหรับ CSPRNG สามารถผ่อนคลายสำหรับกรณีทั่วไปของสตริงสุ่ม แต่ไม่เมื่อเกี่ยวข้องกับความปลอดภัย

คำตอบที่ง่ายปลอดภัยและถูกต้องในการสร้างรหัสผ่านใน PHP คือการใช้RandomLibและอย่าสร้างวงล้อใหม่ ห้องสมุดนี้ได้รับการตรวจสอบโดยผู้เชี่ยวชาญด้านความปลอดภัยของอุตสาหกรรมเช่นเดียวกับตัวฉันเอง

สำหรับนักพัฒนาซอฟต์แวร์ที่ต้องการคิดค้นวิธีแก้ปัญหาของคุณเอง PHP 7.0.0 จะให้บริการrandom_int()เพื่อจุดประสงค์นี้ หากคุณยังคงใช้ PHP 5.x อยู่เราได้เขียนPHP 5 polyfill เพื่อrandom_int()ให้คุณสามารถใช้ API ใหม่ก่อนที่จะปล่อย PHP 7 การใช้ของเราrandom_int()polyfill คืออาจจะปลอดภัยกว่าการเขียนการดำเนินงานของคุณเอง

ด้วยเครื่องกำเนิดเลขจำนวนเต็มแบบสุ่มที่ปลอดภัยในมือการสร้างสตริงแบบสุ่มที่ปลอดภัยนั้นง่ายกว่าพาย:

<?php
/**
 * Generate a random string, using a cryptographically secure 
 * pseudorandom number generator (random_int)
 * 
 * For PHP 7, random_int is a PHP core function
 * For PHP 5.x, depends on https://github.com/paragonie/random_compat
 * 
 * @param int $length      How many characters do we want?
 * @param string $keyspace A string of all possible characters
 *                         to select from
 * @return string
 */
function random_str(
    $length,
    $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
) {
    $str = '';
    $max = mb_strlen($keyspace, '8bit') - 1;
    if ($max < 1) {
        throw new Exception('$keyspace must be at least two characters long');
    }
    for ($i = 0; $i < $length; ++$i) {
        $str .= $keyspace[random_int(0, $max)];
    }
    return $str;
}

2
RandomLib ยังไม่ได้รับการปรับปรุงมานานกว่าสองปีแล้ว ใช้ในการสร้าง PHP ล่าสุด (7.1.25 ในกรณีของฉัน) พ่นคำเตือนการคัดค้านสำหรับmcrypt_*ฟังก์ชั่นต่างๆ ฉันสามารถเห็นเธรดปัญหาที่คุณแยกไลบรารีเนื่องจากไม่สามารถรับ @ircmaxell ได้ แต่ส้อมของคุณบอกว่า 'build ล้มเหลว' ใน Travis คุณต้องการอัปเดตคำตอบนี้ (ซึ่งยังปรากฏบน Google ค่อนข้างสูง)
Janus Bahs Jacquet

1
จับดี! มันจะต้องถูกลบออก
Scott Arciszewski

113

ฉันรู้ว่าคุณกำลังพยายามสร้างรหัสผ่านของคุณในวิธีเฉพาะ แต่คุณอาจต้องการดูวิธีนี้เช่นกัน ...

$bytes = openssl_random_pseudo_bytes(2);

$pwd = bin2hex($bytes);

มันมาจากเว็บไซต์ php.net และสร้างสตริงที่มีความยาวเป็นสองเท่าของจำนวนที่คุณใส่ในฟังก์ชั่น openssl_random_pseudo_bytes ดังนั้นด้านบนจะสร้างรหัสผ่านยาว 4 ตัวอักษร

ในระยะสั้น ...

$pwd = bin2hex(openssl_random_pseudo_bytes(4));

จะสร้างรหัสผ่านยาว 8 ตัวอักษร

โปรดทราบว่ารหัสผ่านจะมีเพียงตัวเลข 0-9 และตัวอักษรขนาดเล็กสุดเท่านั้น!


13
หากคุณต้องการรหัสผ่านที่เป็นตัวพิมพ์ใหญ่ตัวพิมพ์เล็กและตัวเลขลองสิ่งนี้: gist.github.com/zyphlar/7217f566fc83a9633959
willbradley

@ زيادพูดว่าใคร หากเครื่องกำเนิดไฟฟ้าใช้ไบต์ 7 บิตฉันจะเห็นด้วยกับคุณ แต่openssl_random_pseudo_bytes()เป็นเครื่องกำเนิดไบนาติเรนเนสของไบนารีแบบเต็มประสิทธิภาพและไม่ต้องการการสับเพิ่มเติม นอกจากนี้ฉันจะใช้โอกาสที่จะชี้ให้เห็นว่ามันเป็นอันตรายที่จะสมมติว่าวิธีการเข้ารหัสแบบซ้อนหลายวิธีจะทำให้เกิดการสุ่มมากขึ้นในบางกรณีมันอาจจะเป็นสิ่งที่ตรงกันข้ามเพราะการชนกันของการสะสมกัญชา
Havenard

56

รหัสจิ๋วที่มี2 บรรทัด

ตัวอย่าง: http://codepad.org/5rHMHwnH

function rand_string( $length ) {

    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return substr(str_shuffle($chars),0,$length);

}

echo rand_string(8);

ด้วย rand_string คุณสามารถกำหนดจำนวนอักขระที่จะสร้างได้


21
ดีแม้ว่าคุณจะไม่ได้รับตัวละครซ้ำ ๆ โดยใช้วิธีการนี้ซึ่งอาจไม่เป็นที่ต้องการ
กุ๊ย

11
ฟังก์ชั่นนี้แย่มากสำหรับการสร้างรหัสผ่านที่ยาว ขั้นแรกหาก $ length ยาวกว่าสตริง $ chars คุณจะไม่ได้รับสตริงตราบเท่าที่ความยาวที่คุณป้อน แต่ความยาวของสตริง chars นอกจากนี้คุณจะได้รับการรับประกันเพียงหนึ่งในตัวละครแต่ละตัวโดยไม่ซ้ำกัน นอกจากนี้ยังไม่รับประกันการใช้ตัวพิมพ์ใหญ่หรือตัวเลขซึ่งค่อนข้างบ่อยตามข้อกำหนด (ยกเว้นกรณีที่ความยาวของคุณมากกว่า 26 เนื่องจากข้อผิดพลาดก่อนหน้านี้)
Programter

แล้ว @Programster และ @Hobo นี้ล่ะ substr(str_shuffle(str_repeat($chars,$length)),0,$length);
Charles-Édouard Coste

@ Charles-EdouardCoste ดูเหมือนว่าจะทำงานได้ดีพอ (โดยเฉพาะถ้าคุณโยนตัวอักษรพิเศษบางตัว) แม้ว่ามันจะยังไม่รับประกันอย่างน้อยหนึ่งตัวละครแต่ละประเภท สิ่งเดียวที่ทำให้ฉันรำคาญใจคือการทำซ้ำอักขระทั้งหมดที่กำหนดโดยความยาวของรหัสผ่านที่ต้องการ แต่เพื่อให้แน่ใจว่าตัวอักษรในรหัสผ่านที่สร้างขึ้นไม่จำเป็นต้องไม่ซ้ำกันและไม่มีผลกระทบต่อประสิทธิภาพที่เห็นได้ชัดเจนในการใช้เพียงครั้งเดียว
โปรแกรม

ฉันเห็นด้วย มันอาจจะดีกว่าถ้าไม่เลือกอัลกอริทึมกับจำนวนบรรทัด อย่างไรก็ตามถ้าเป้าหมายหลักคือการสร้างรหัสผ่านชั่วคราวเมื่อสร้างผู้ใช้ใหม่บนเว็บไซต์สิ่งนี้จะตอบสนองความต้องการฉันเดา
Charles-Édouard Coste

40

ถ้าคุณอยู่บน PHP7 คุณสามารถใช้random_int()ฟังก์ชัน:

function generate_password($length = 20){
  $chars =  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
            '0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';

  $str = '';
  $max = strlen($chars) - 1;

  for ($i=0; $i < $length; $i++)
    $str .= $chars[random_int(0, $max)];

  return $str;
}

คำตอบเก่าด้านล่าง:

function generate_password($length = 20){
  $chars =  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
            '0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';

  $str = '';
  $max = strlen($chars) - 1;

  for ($i=0; $i < $length; $i++)
    $str .= $chars[mt_rand(0, $max)];

  return $str;
}

12
อย่าใช้mt_randเพื่อสร้างรหัสผ่าน
CodesInChaos

2
@CodesInChaos จะดีกว่า rand () ซึ่งเป็นตัวอย่างที่ใช้ข้างต้น openssl_random_pseudo_bytes () เป็นที่ต้องการตามคู่มือ PHP
willbradley

4
@willbradley คุณภาพของเมล็ดพันธุ์นั้นแย่เหมือนmt_randกันดังนั้นจึงยังไม่เหมาะสมสำหรับการใช้งานด้านความปลอดภัยใด ๆ
CodesInChaos

2
คุณเห็นนี่เป็นสิ่งที่ทำให้ฉันรำคาญ + ChaosInCodes คุณยังไม่ได้ดูคำถามคุณเพิ่งทำแถลงการณ์ทั่วไปซ้ำแล้วซ้ำอีกเป็นจำนวนมากของความเชื่อที่ไม่ดี กล่าวโดยย่อ: คำแนะนำที่ถูกต้องสำหรับคำถามที่ต่างออกไปโดยสิ้นเชิง รหัสผ่านแบบสุ่มนั้นใช้ได้ พวกเขาอาจใช้ "x" เท่านั้น ค่อนข้างตรงไปตรงมาถ้าคุณกำลังออกแบบระบบของคุณโดยไม่มีการล็อกตามกำหนดเวลาและการตรวจจับ DOS และ "x พยายามแล้ว -> ถูกล็อค" จากนั้นคุณก็ทำผิด มันเป็นไปไม่ได้ที่จะคาดเดารหัสผ่าน mt_rand พร้อมกับมาตรการดังกล่าว การใช้ mt_rand ในทางกลับกันจะไม่ทำให้ง่ายขึ้นในการบังคับใช้รหัสผ่าน มันแค่จะไม่
Mr Heelis

1
ฉันจะไม่ใช้ \ in$chars
CONvid19

36

ในหนึ่งบรรทัด:

substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') , 0 , 10 )

11
การทำเช่นนี้จะป้องกันการใช้ตัวอักษรเดียวกันซ้ำ ๆ ในขณะที่ตัวอักษรสลับไปมา แต่ไม่เกิดขึ้นมากกว่าหนึ่งครั้ง
nickdnk

8
ไม่จำเป็นต้องพูดไม่มีใครควรปรับฟังก์ชั่นการสร้างรหัสผ่านให้เหมาะสมตามจำนวนบรรทัด แม้ว่าการใช้ RNG นี้จะปลอดภัย (ไม่ใช่) การหลีกเลี่ยงอักขระซ้ำ ๆ ในขณะที่สร้างรหัสผ่าน 10 ตัวอักษรจะทำให้คุณลดระดับเอนโทรปี ~ 52 บิตจากเอนโทรปี ~ 50 บิตเพื่อเอนโทรปี หากคุณขยายออกไปถึง 20 ตัวอักษรการไม่ทำซ้ำจะทำให้คุณลดระดับจาก ~ 103 บิตเป็น ~ 94 บิต (~ 512x เร็วกว่าที่จะถอดรหัส)
Jeremy Banks

1
วิธีนี้ทำให้ฉันนึกถึงข้อบกพร่องใน Enigma code Lol
เกลียดชัง

4
substr(str_shuffle(str_repeat($chars,$length)),0,$length); คืนค่าเอนโทรปี
Charles-Édouard Coste

27

ทางออกที่ดีที่สุดของคุณคือห้องสมุด RandomLib โดย ircmaxell

ตัวอย่างการใช้งาน:

$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));

$passwordLength = 8; // Or more
$randomPassword = $generator->generateString($passwordLength);

มันสร้างสตริงที่สุ่มมากขึ้นกว่าฟังก์ชั่นการสุ่มแบบปกติเช่นshuffle()และrand()(ซึ่งเป็นสิ่งที่คุณต้องการข้อมูลที่ละเอียดอ่อนเช่นรหัสผ่านเกลือและกุญแจ)


4
นี่คือคำตอบที่ถูกต้อง อย่าใช้หรือrand() mt_rand()
Scott Arciszewski

1
อาจเป็นคำตอบที่ปลอดภัยที่สุด (ไม่แน่ใจว่ามันเปรียบเทียบกับrandom_bytes) แต่นั่นไม่ได้ทำให้randคำตอบไม่ถูกต้อง
Cerbrus


8
@Cerbrus: แน่ใจว่าคำตอบนี้ไม่ได้ทำให้คำตอบใช้rand()ไม่ถูกต้อง พวกเขาไม่ถูกต้องทั้งหมดด้วยตัวเอง!
Deduplicator

14

คุณต้องการstrlen($alphabet)ไม่ใช่countค่าคงที่alphabet(เทียบเท่า'alphabet')

อย่างไรก็ตามrandไม่ใช่ฟังก์ชันสุ่มที่เหมาะสมสำหรับจุดประสงค์นี้ สามารถคาดการณ์เอาต์พุตได้อย่างง่ายดายเนื่องจากมีการหว่านเมล็ดโดยนัยกับเวลาปัจจุบัน นอกจากนี้randยังไม่มีการเข้ารหัสที่ปลอดภัย ดังนั้นจึงค่อนข้างง่ายที่จะกำหนดสถานะภายในของมันจากเอาต์พุต

แต่อ่านจาก/dev/urandomเพื่อรับข้อมูลแบบสุ่มเข้ารหัส


14

ฉันจะโพสต์คำตอบเพราะบางคำตอบที่มีอยู่ใกล้ แต่มีหนึ่งใน:

  • พื้นที่อักขระที่เล็กกว่าที่คุณต้องการเพื่อให้การบังคับใช้เดรัจฉานง่ายขึ้นหรือรหัสผ่านต้องยาวขึ้นสำหรับเอนโทรปีเดียวกัน
  • RNGว่าจะไม่ถือว่าเป็นที่เชื่อถือได้เข้ารหัส
  • ข้อกำหนดสำหรับห้องสมุดบุคคลที่สามและฉันคิดว่ามันน่าสนใจที่จะแสดงสิ่งที่อาจต้องทำด้วยตัวเอง

คำตอบนี้จะหลีกเลี่ยงcount/strlenปัญหาเนื่องจากความปลอดภัยของรหัสผ่านที่สร้างขึ้นอย่างน้อย IMHO จะผ่านพ้นวิธีที่คุณได้รับ ฉันจะสมมติ PHP> 5.3.0 ด้วย

ลองแยกปัญหาออกเป็นส่วนต่างๆซึ่ง ได้แก่ :

  1. ใช้แหล่งความปลอดภัยของการสุ่มเพื่อรับข้อมูลแบบสุ่ม
  2. ใช้ข้อมูลนั้นและแสดงว่าเป็นสตริงที่พิมพ์ได้

สำหรับส่วนแรก, PHP> 5.3.0 openssl_random_pseudo_bytesให้ฟังก์ชั่น โปรดทราบว่าในขณะที่ระบบส่วนใหญ่ใช้อัลกอริทึมที่แข็งแกร่งของการเข้ารหัสคุณต้องตรวจสอบดังนั้นเราจะใช้กระดาษห่อ:

/**
 * @param int $length
 */
function strong_random_bytes($length)
{
    $strong = false; // Flag for whether a strong algorithm was used
    $bytes = openssl_random_pseudo_bytes($length, $strong);

    if ( ! $strong)
    {
        // System did not use a cryptographically strong algorithm 
        throw new Exception('Strong algorithm not available for PRNG.');
    }        

    return $bytes;
}

สำหรับส่วนที่สองเราจะใช้base64_encodeเนื่องจากใช้สตริงไบต์และจะสร้างชุดอักขระที่มีตัวอักษรใกล้เคียงกับที่ระบุในคำถามดั้งเดิมมาก ถ้าเราไม่ได้คิดมี+, /และ=ตัวละครที่ปรากฏในสตริงสุดท้ายและเราต้องการผลอย่างน้อย$nตัวละครยาวเราก็สามารถใช้:

base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));

3/4ปัจจัยที่เป็นผลมาจากความจริงที่ว่า base64 เข้ารหัสผลลัพธ์ในสตริงที่มีความยาวอย่างน้อยหนึ่งในสามที่ใหญ่กว่าสตริงไบต์ที่ ผลลัพธ์จะถูกต้องสำหรับ$nการเป็นทวีคูณของ 4 และสูงสุด 3 ตัวอักษรเป็นอย่างอื่น เนื่องจากอักขระพิเศษส่วนใหญ่เป็นอักขระการขยาย=ถ้าเราด้วยเหตุผลบางอย่างมีข้อ จำกัด ว่ารหัสผ่านมีความยาวที่แน่นอนดังนั้นเราจึงสามารถตัดให้เหลือความยาวตามที่เราต้องการ โดยเฉพาะอย่างยิ่งเนื่องจากมีการกำหนด$nรหัสผ่านทั้งหมดจะลงท้ายด้วยหมายเลขเดียวกันดังนั้นผู้โจมตีที่เข้าถึงรหัสผ่านผลลัพธ์จะมีอักขระน้อยกว่า 2 ตัวในการเดา


สำหรับเครดิตพิเศษถ้าเราต้องการพบสเป็คที่แน่นอนเหมือนในคำถามของ OP เราจะต้องทำงานเพิ่มอีกนิดหน่อย ฉันจะทิ้งวิธีการแปลงฐานที่นี่และไปด้วยวิธีที่รวดเร็วและสกปรก ทั้งคู่จำเป็นต้องสร้างการสุ่มมากขึ้นกว่าที่จะใช้ในผลลัพธ์ต่อไปเนื่องจากมีตัวอักษรยาว 62 รายการ

สำหรับอักขระพิเศษในผลลัพธ์เราสามารถทิ้งมันจากสตริงผลลัพธ์ ถ้าเราเริ่มต้นด้วย 8 ไบต์ในไบต์สตริงของเราแล้วมากถึง 25% ของอักขระเบส 64 จะเป็นอักขระ "ไม่พึงปรารถนา" เหล่านี้ดังนั้นการทิ้งอักขระเหล่านี้ส่งผลให้เกิดสตริงไม่สั้นกว่าที่ต้องการ จากนั้นเราสามารถตัดให้สั้นลงเพื่อให้ได้ความยาวที่แน่นอน:

$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);

หากคุณสร้างรหัสผ่านที่ยาวขึ้นอักขระการขยาย=จะสร้างสัดส่วนของผลกลางที่เล็กลงและเล็กลงเพื่อให้คุณสามารถใช้วิธีการแบบลีนได้ถ้าการระบายเอนโทรปีที่ใช้สำหรับ PRNG นั้นเป็นเรื่องที่น่ากังวล


1
ขอบคุณสำหรับการเพิ่มนี้ ไม่พบคำตอบที่มีอยู่ซึ่งopenssl_random_pseudo_bytesสามารถให้ผลลัพธ์ที่อ่อนแอ ฉันไม่ได้ตระหนักถึงกรณีนี้
Jeremy Banks

12

base_convert(uniqid('pass', true), 10, 36);

เช่น. e0m6ngefmj4

แก้ไข

ดังที่ฉันได้กล่าวไว้ในความคิดเห็นความยาวหมายความว่าการโจมตีด้วยเดรัจฉานจะทำงานได้ดีขึ้นเมื่อเทียบกับการโจมตีตามจังหวะเวลาดังนั้นมันจึงไม่เกี่ยวข้องกับการกังวลว่า ความปลอดภัยโดยเฉพาะสำหรับกรณีการใช้งานนี้จำเป็นต้องเสริมความสะดวกในการใช้งานดังนั้นวิธีการแก้ปัญหาข้างต้นนั้นดีพอสำหรับปัญหาที่ต้องการ

อย่างไรก็ตามในกรณีที่คุณสะดุดคำตอบนี้ในขณะที่ค้นหาตัวสร้างสตริงแบบสุ่มที่ปลอดภัย (เพราะฉันคิดว่าบางคนมีพื้นฐานจากคำตอบ) สำหรับสิ่งต่าง ๆ เช่นสร้างโทเค็นนี่คือลักษณะของตัวสร้างรหัสดังกล่าว:

function base64urlEncode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function secureId($length = 32) {

    if (function_exists('openssl_random_pseudo_bytes')) {
        $bytes = openssl_random_pseudo_bytes($length);
        return rtrim(strtr(base64_encode($bytes), '+/', '0a'), '=');
    }
    else { // fallback to system bytes

        error_log("Missing support for openssl_random_pseudo_bytes");

        $pr_bits = '';

        $fp = @fopen('/dev/urandom', 'rb');
        if ($fp !== false) {
            $pr_bits .= @fread($fp, $length);
            @fclose($fp);
        }

        if (strlen($pr_bits) < $length) {
            error_log('unable to read /dev/urandom');
            throw new \Exception('unable to read /dev/urandom');
        }

        return base64urlEncode($pr_bits);
    }
}

1
PS - นี่คือ PHP เพียงแค่ใช้ \ เพื่อแสดงถึงเนมสเปซส่วนกลาง
Bob Gregor

ยกเว้นว่า uniqid จะไม่ปลอดภัยแบบเข้ารหัส ใช้ rand () แทน: base_convert (rand (78364164096, 2821109907455), 10, 36);
Benubird

7
@Benubird rand () ไม่ปลอดภัยแบบเข้ารหัสตามคู่มือ PHP คู่มือแนะนำ openssl_random_pseudo_bytes () แทน
willbradley

สำหรับกรณีการใช้งานส่วนใหญ่โดยเฉพาะอย่างยิ่งที่ผู้โจมตีไม่สามารถเข้าถึงเวลาที่แน่นอนนี้เป็นอย่างดีและสร้างรหัสผ่าน "ชั่วคราว" ที่เป็นมิตรกับมนุษย์มากขึ้นหรือน้อยลง ถ้าเราจะนำสิ่งนี้ไปให้ไกลสุดขีดความยาวของที่นี่จะยุ่งยากมากกว่านี้แล้วฟังก์ชั่นใดที่ใช้ในการสร้างเลขสุ่ม
srcspider

ฉันได้เพิ่มตัวอย่างสำหรับการสร้างสตริงที่ปลอดภัยอย่างสมบูรณ์สำหรับผู้ที่สนใจ แต่ไม่แนะนำให้ใช้เมื่อสร้างรหัสผ่านชั่วคราวสำหรับผู้ใช้ แม้จะใช้รุ่นที่ปลอดภัยปัญหาความยาวก็ยังคงมีผลอยู่
srcspider

9

อีกอันหนึ่ง (ลินุกซ์เท่านั้น)

function randompassword()
{
    $fp = fopen ("/dev/urandom", 'r');
    if (!$fp) { die ("Can't access /dev/urandom to get random data. Aborting."); }
    $random = fread ($fp, 1024); # 1024 bytes should be enough
    fclose ($fp);
    return trim (base64_encode ( md5 ($random, true)), "=");
}

1
การอ่าน 1024 ไบต์เพื่อบีบอัดลงในแฮชการเข้ารหัสแบบ 128 บิตของเอนโทรปีนั้นสิ้นเปลืองเพียงเล็กน้อย นอกจากนี้ยังมีfread()บัฟเฟอร์ถึง 8192 ไบต์ตามค่าเริ่มต้นดังนั้นคุณจะต้องอ่านค่าจำนวนมาก/dev/urandomด้วยโค้ดที่ให้มา สิ่งนี้จะไม่ทำงานบน Windows ความรุ่งโรจน์สำหรับการใช้ CSPRNG
Scott Arciszewski

9

เป็นคนฉลาดน้อย:

function strand($length){
  if($length > 0)
    return chr(rand(33, 126)) . strand($length - 1);
}

ตรวจสอบได้ที่นี่


7

ใช้รหัสง่ายๆนี้เพื่อสร้างรหัสผ่านความยาว 12 หลัก

$password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789';
$password = substr(str_shuffle($password_string), 0, 12);

อันที่จริงมันผิด (มาก?) จริง ๆ แล้วมันใช้อักขระทุกตัวจากตัวอักษรเพียงครั้งเดียวเท่านั้นดังนั้นจึงลดขนาดของค่าที่เป็นไปได้ทั้งหมด (เกี่ยวข้องกับการแคร็ก)
Radoslav Bodo

6

ลองใช้ตัวอักษรตัวใหญ่ตัวเล็กตัวเลขและอักขระพิเศษ

function generatePassword($_len) {

    $_alphaSmall = 'abcdefghijklmnopqrstuvwxyz';            // small letters
    $_alphaCaps  = strtoupper($_alphaSmall);                // CAPITAL LETTERS
    $_numerics   = '1234567890';                            // numerics
    $_specialChars = '`~!@#$%^&*()-_=+]}[{;:,<.>/?\'"\|';   // Special Characters

    $_container = $_alphaSmall.$_alphaCaps.$_numerics.$_specialChars;   // Contains all characters
    $password = '';         // will contain the desired pass

    for($i = 0; $i < $_len; $i++) {                                 // Loop till the length mentioned
        $_rand = rand(0, strlen($_container) - 1);                  // Get Randomized Length
        $password .= substr($_container, $_rand, 1);                // returns part of the string [ high tensile strength ;) ] 
    }

    return $password;       // Returns the generated Pass
}

สมมติว่าเราต้องการ 10 Digit Pass

echo generatePassword(10);  

ตัวอย่างผลลัพธ์:

, IZCQ_IV \ 7

@wlqsfhT (ง

1 8 + 1 \ 4 @ UD


randฟังก์ชั่นไม่ได้จริงเข้ารหัสรักษาความปลอดภัยดังนั้นจึงอาจจะค่อนข้างมีความเสี่ยงในการสร้างรหัสผ่านที่ใช้มัน
jeteon

3

ด่วนหนึ่งเดียว รูปแบบเรียบง่ายสะอาดและสอดคล้องกันหากเป็นสิ่งที่คุณต้องการ

$pw = chr(mt_rand(97,122)).mt_rand(0,9).chr(mt_rand(97,122)).mt_rand(10,99).chr(mt_rand(97,122)).mt_rand(100,999);

3

นี่เป็นคำตอบอื่น ๆ ในหน้านี้ https://stackoverflow.com/a/21498316/525649

คำตอบนี้สร้างเพียงตัวอักษรฐานสิบหก, 0-9,a-f. สำหรับสิ่งที่ไม่เหมือนเลขฐานสิบหกลองสิ่งนี้:

str_shuffle(
  rtrim(
    base64_encode(bin2hex(openssl_random_pseudo_bytes(5))),
    '='
  ). 
  strtoupper(bin2hex(openssl_random_pseudo_bytes(7))).
  bin2hex(openssl_random_pseudo_bytes(13))
)
  • base64_encode ส่งคืนการแพร่กระจายของตัวอักษรและตัวเลขที่กว้างขึ้น
  • rtrimลบ=บางครั้งในตอนท้าย

ตัวอย่าง:

  • 32eFVfGDg891Be5e7293e54z1D23110M3ZU3FMjb30Z9a740Ej0jz4
  • b280R72b48eOm77a25YCj093DE5d9549Gc73Jg8TdD9Z0Nj4b98760
  • 051b33654C0Eg201cfW0e6NA4b9614ze8D2FN49E12Y0zY557aUCb8
  • y67Q86ffd83G0z00M0Z152f7O2ADcY313gD7a774fc5FF069zdb5b7

สิ่งนี้ไม่สามารถกำหนดค่าได้มากสำหรับการสร้างอินเทอร์เฟซสำหรับผู้ใช้ แต่สำหรับบางวัตถุประสงค์ที่ไม่เป็นไร เพิ่มจำนวนตัวอักษรเพื่ออธิบายการขาดอักขระพิเศษ


3
  1. สร้างไฟล์ด้วยรหัสนี้ในนั้น
  2. เรียกว่าเหมือนในความคิดเห็น

    <?php 
    
    /**
    * @usage  :
    *       include_once($path . '/Password.php');
    *       $Password = new Password;
    *       $pwd = $Password->createPassword(10);
    *       return $pwd;
    * 
    */
    
    class Password {
    
        public function createPassword($length = 15) {
            $response = [];
            $response['pwd'] = $this->generate($length);
            $response['hashPwd'] = $this->hashPwd( $response['pwd'] );
            return $response;
        }
    
        private function generate($length = 15) {
            $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(){}/?,><";
            return substr(str_shuffle($chars),0,$length);
        }
    
        private function hashPwd($pwd) {
            return hash('sha256', $pwd);
        }
    
    }
    
    ?>

2

ฉันสร้างสคริปต์รหัสผ่านที่ครอบคลุมและปลอดภัยยิ่งขึ้น สิ่งนี้จะสร้างการรวมกันของตัวพิมพ์ใหญ่สองตัวตัวพิมพ์เล็กสองตัวสองตัวตัวเลขสองตัวและอักขระพิเศษสองตัว รวม 8 ตัวอักษร

$char = [range('A','Z'),range('a','z'),range(0,9),['*','%','$','#','@','!','+','?','.']];
$pw = '';
for($a = 0; $a < count($char); $a++)
{
    $randomkeys = array_rand($char[$a], 2);
    $pw .= $char[$a][$randomkeys[0]].$char[$a][$randomkeys[1]];
}
$userPassword = str_shuffle($pw);

1
//define a function. It is only 3 lines!   
function generateRandomPassword($length = 5){
    $chars = "0123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
    return substr(str_shuffle($chars),0,$length);
}

//usage
echo generateRandomPassword(5); //random password legth: 5
echo generateRandomPassword(6); //random password legth: 6
echo generateRandomPassword(7); //random password legth: 7

อันที่จริงมันผิด (มาก?) จริง ๆ แล้วมันใช้อักขระทุกตัวจากตัวอักษรเพียงครั้งเดียวเท่านั้นดังนั้นจึงลดขนาดของค่าที่เป็นไปได้ทั้งหมด (เกี่ยวข้องกับการแคร็ก)
Radoslav Bodo

0

สร้างรหัสผ่านที่คาดเดายากที่มีความยาว 8 ซึ่งประกอบด้วยตัวอักษรตัวพิมพ์เล็กอย่างน้อยหนึ่งตัวอักษรตัวพิมพ์ใหญ่หนึ่งตัวตัวอักษรหนึ่งตัวและตัวอักษรพิเศษหนึ่งตัว คุณสามารถเปลี่ยนความยาวในรหัสได้เช่นกัน

function checkForCharacterCondition($string) {
    return (bool) preg_match('/(?=.*([A-Z]))(?=.*([a-z]))(?=.*([0-9]))(?=.*([~`\!@#\$%\^&\*\(\)_\{\}\[\]]))/', $string);
}

$j = 1;

function generate_pass() {
    global $j;
    $allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_{}[]';
    $pass = '';
    $length = 8;
    $max = mb_strlen($allowedCharacters, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $pass .= $allowedCharacters[random_int(0, $max)];
    }

    if (checkForCharacterCondition($pass)){
        return '<br><strong>Selected password: </strong>'.$pass;
    }else{
        echo 'Iteration '.$j.':  <strong>'.$pass.'</strong>  Rejected<br>';
        $j++;
        return generate_pass();
    }

}

echo generate_pass();

0

ฟังก์ชั่นนี้จะสร้างรหัสผ่านตามกฎในพารามิเตอร์

function random_password( $length = 8, $characters = true, $numbers = true, $case_sensitive = true, $hash = true ) {

    $password = '';

    if($characters)
    {
        $charLength = $length;
        if($numbers) $charLength-=2;
        if($case_sensitive) $charLength-=2;
        if($hash) $charLength-=2;
        $chars = "abcdefghijklmnopqrstuvwxyz";
        $password.= substr( str_shuffle( $chars ), 0, $charLength );
    }

    if($numbers)
    {
        $numbersLength = $length;
        if($characters) $numbersLength-=2;
        if($case_sensitive) $numbersLength-=2;
        if($hash) $numbersLength-=2;
        $chars = "0123456789";
        $password.= substr( str_shuffle( $chars ), 0, $numbersLength );
    }

    if($case_sensitive)
    {
        $UpperCaseLength = $length;
        if($characters) $UpperCaseLength-=2;
        if($numbers) $UpperCaseLength-=2;
        if($hash) $UpperCaseLength-=2;
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $password.= substr( str_shuffle( $chars ), 0, $UpperCaseLength );
    }

    if($hash)
    {
        $hashLength = $length;
        if($characters) $hashLength-=2;
        if($numbers) $hashLength-=2;
        if($case_sensitive) $hashLength-=2;
        $chars = "!@#$%^&*()_-=+;:,.?";
        $password.= substr( str_shuffle( $chars ), 0, $hashLength );
    }

    $password = str_shuffle( $password );
    return $password;
}

0

ที่นี่ฉันใช้เวลาที่ผู้ช่วยสร้างรหัสผ่านแบบสุ่มแบบสุ่ม

มันช่วยให้มั่นใจได้ว่ารหัสผ่านมีตัวเลขตัวอักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็กรวมทั้งอักขระพิเศษขั้นต่ำ 3 ตัว

ความยาวของรหัสผ่านจะอยู่ระหว่าง 11 ถึง 30

function plainPassword(): string
{
    $numbers = array_rand(range(0, 9), rand(3, 9));
    $uppercase = array_rand(array_flip(range('A', 'Z')), rand(2, 8));
    $lowercase = array_rand(array_flip(range('a', 'z')), rand(3, 8));
    $special = array_rand(array_flip(['@', '#', '$', '!', '%', '*', '?', '&']), rand(3, 5));

    $password = array_merge(
        $numbers,
        $uppercase,
        $lowercase,
        $special
    );

    shuffle($password);

    return implode($password);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.