ความสามารถในการเดาค่าถัดไปจากrand
นั้นเชื่อมโยงกับความสามารถในการพิจารณาสิ่งที่srand
ถูกเรียกด้วย โดยเฉพาะการเพาะที่srand
มีจำนวนที่กำหนดไว้จะทำให้ได้ผลลัพธ์ที่คาดการณ์ได้ ! จากพร้อมต์ PHP แบบโต้ตอบ:
[charles@charles-workstation ~]$ php -a
Interactive shell
php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php >
นี่ไม่ใช่แค่ความบังเอิญ PHP เวอร์ชันส่วนใหญ่*บนแพลตฟอร์มส่วนใหญ่**จะสร้างลำดับ 97, 97, 39, 77, 93 เมื่อใช้srand
กับ 1024
เพื่อความชัดเจนนี่ไม่ใช่ปัญหาของ PHP นี่เป็นปัญหาของการใช้งานrand
ตัวมันเอง ปัญหาเดียวกันปรากฏในภาษาอื่น ๆ ที่ใช้การใช้งานเดียวกัน (หรือคล้ายกัน) รวมถึง Perl
เคล็ดลับคือ PHP รุ่นใด ๆ ที่มีสติจะมีค่าเริ่มต้นที่srand
มีค่า "ไม่ทราบ" โอ้ แต่มันไม่เป็นที่รู้จักจริงๆ จากext/standard/php_rand.h
:
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
ดังนั้นจึงเป็นทางคณิตศาสตร์บางคนที่มีtime()
, PID และผลจากการที่กำหนดไว้ในphp_combined_lcg
ext/standard/lcg.c
ฉันจะไม่ไปที่นี่เหมือนกันดวงตาของฉันจ้องมองและฉันก็ตัดสินใจหยุดล่าสัตว์
Googling เล็กน้อยแสดงให้เห็นว่าพื้นที่อื่น ๆ ของ PHP ไม่มีคุณสมบัติการสร้างแบบสุ่มที่ดีที่สุดและการเรียกร้องให้php_combined_lcg
โดดเด่นโดยเฉพาะการวิเคราะห์บิตนี้:
ฟังก์ชั่นนี้ไม่เพียง แต่ ( gettimeofday
) ส่งเรากลับเวลาประทับของเซิร์ฟเวอร์ที่แม่นยำบนแผ่นเงินมันยังเพิ่มใน LCG เอาท์พุทถ้าเราขอ "เอนโทรปีมากขึ้น" (จากของ PHP uniqid
)
ใช่ว่า uniqid
ดูเหมือนว่าค่าของphp_combined_lcg
คือสิ่งที่เราเห็นเมื่อเราดูเลขฐานสิบหกที่เกิดขึ้นหลังจากการเรียกuniqid
ด้วยอาร์กิวเมนต์ที่สองตั้งค่าที่แท้จริง
ตอนนี้เราอยู่ที่ไหน
โอ้ใช่. srand
.
ดังนั้นถ้ารหัสที่คุณกำลังพยายามที่จะคาดการณ์ค่าสุ่มจากไม่ได้โทรหาsrand
คุณกำลังจะต้องกำหนดค่าให้โดยphp_combined_lcg
ที่คุณจะได้รับ (ทางอ้อม?) uniqid
ผ่านการเรียกไปยัง ด้วยค่าที่มีอยู่ในมือจึงเป็นไปได้ที่จะบังคับค่าที่เหลือ - เดรัจฉาน - time()
PID และคณิตศาสตร์ ปัญหาความปลอดภัยที่เชื่อมโยงเป็นเรื่องเกี่ยวกับการแบ่งเซสชัน แต่เทคนิคเดียวกันจะทำงานที่นี่ อีกครั้งจากบทความ:
นี่เป็นบทสรุปของขั้นตอนการโจมตีที่อธิบายไว้ข้างต้น:
- รอให้เซิร์ฟเวอร์รีบูต
- ดึงค่า uniqid
- กำลังดุร้ายกับเมล็ด RNG จากสิ่งนี้
- สำรวจสถานะออนไลน์เพื่อรอให้เป้าหมายปรากฏ
- การสอดแทรกสถานะสอดแทรกพร้อมโพล uniqid เพื่อติดตามเวลาเซิร์ฟเวอร์ปัจจุบันและค่า RNG
- กำลังประมวลผล ID เซสชันที่ดุร้ายกับเซิร์ฟเวอร์โดยใช้เวลาและช่วงค่า RNG ที่สร้างขึ้นในการทำโพล
เพียงแทนที่ขั้นตอนสุดท้ายตามต้องการ
(ปัญหาด้านความปลอดภัยนี้มีการรายงานในเวอร์ชัน PHP ก่อนหน้า (5.3.2) กว่าที่เรามีในปัจจุบัน (5.3.6) ดังนั้นจึงเป็นไปได้ว่าพฤติกรรมของuniqid
และ / หรือphp_combined_lcg
มีการเปลี่ยนแปลงดังนั้นเทคนิคเฉพาะนี้อาจไม่สามารถใช้งานได้อีกต่อไป YMMV.)
ในทางกลับกันถ้ารหัสที่คุณพยายามโทรออกsrand
ผลิตภัณฑ์ด้วยตนเองเว้นแต่ว่าพวกเขากำลังใช้บางสิ่งที่ดีกว่าผลที่ตามมาหลายครั้งphp_combined_lcg
คุณอาจจะมีเวลาที่ง่ายกว่ามากในการคาดเดาค่าและการเพาะในท้องถิ่นของคุณ เครื่องกำเนิดไฟฟ้าที่มีหมายเลขที่ถูกต้อง คนส่วนใหญ่ที่จะโทรด้วยตนเองsrand
จะไม่ทราบว่าความน่ากลัวของความคิดนี้เป็นอย่างไรและดังนั้นจึงไม่น่าจะใช้ค่าที่ดีกว่า
เป็นที่น่าสังเกตว่าmt_rand
ปัญหาเดียวกันก็เกิดขึ้นเช่นกัน การเพาะmt_srand
ด้วยค่าที่ทราบจะทำให้ได้ผลลัพธ์ที่คาดการณ์ได้ การอ้างอิงเอนโทรปีของคุณopenssl_random_pseudo_bytes
อาจเป็นทางออกที่ปลอดภัยกว่า
tl; dr:เพื่อให้ได้ผลลัพธ์ที่ดีที่สุดอย่าเริ่มต้นตัวสร้างตัวเลขสุ่ม PHP และเพื่อประโยชน์ของคุณอย่าเปิดเผยuniqid
ต่อผู้ใช้ การทำอย่างใดอย่างหนึ่งหรือทั้งสองอย่างนี้อาจทำให้หมายเลขสุ่มของคุณเดาได้ง่ายขึ้น
อัพเดทสำหรับ PHP 7:
PHP 7.0 แนะนำrandom_bytes
และrandom_int
เป็นฟังก์ชั่นหลัก พวกเขาใช้การใช้งาน CSPRNG ของระบบพื้นฐานทำให้พวกเขาเป็นอิสระจากปัญหาที่ตัวสร้างหมายเลขสุ่มมีเมล็ด มันคล้ายกันอย่างมีประสิทธิภาพopenssl_random_pseudo_bytes
เพียงโดยไม่ต้องมีส่วนขยายที่จะติดตั้ง polyfill สามารถใช้ได้สำหรับการ PHP5
*: แพทช์รักษาความปลอดภัยของซูโฮซินเปลี่ยนพฤติกรรมของสิ่งนั้นrand
และmt_rand
พวกมันจะทำการรีเรสกับการโทรทุกครั้ง Suhosin ให้บริการโดยบุคคลที่สาม การแจกแจงลินุกซ์บางอย่างรวมไว้ในแพ็คเกจ PHP อย่างเป็นทางการโดยค่าเริ่มต้นในขณะที่คนอื่น ๆ ทำให้มันเป็นตัวเลือกและคนอื่นไม่สนใจมัน
**: ขึ้นอยู่กับแพลตฟอร์มและการเรียกใช้ไลบรารีพื้นฐานลำดับที่แตกต่างกันจะถูกสร้างขึ้นจากที่นี่ แต่ผลลัพธ์จะยังคงสามารถทำซ้ำได้เว้นแต่จะมีการใช้ปะแก้ของ Suhosin