Score:0

CSPRNG ใน Javascript?

ธง cn

ฉันกำลังพยายามรับตัวเลขที่ค่อนข้างยาวแบบสุ่มและคาดเดาไม่ได้ (± 20-25 หลัก) โดยใช้ Javascript (สร้างโดยไคลเอนต์ของผู้ใช้) ให้เร็วและเบาที่สุด โซลูชันนี้มีความน่าเชื่อถือ แข็งแกร่ง และปลอดภัยเพียงพอหรือไม่

เมื่อเปิดหน้าออนไลน์ การประทับเวลา 13 หลักจะถูกเก็บไว้ ตัวจับเวลาจะกำหนดจำนวนมิลลิวินาทีก่อนที่ผู้ใช้จะคลิก "ตกลง" (สมมติว่าเขามีข้อความสั้นให้อ่านหรืออย่างอื่นที่ต้องทำ) คอลเลกชันของ 'พิกเซล' ที่มองไม่เห็น 100 พิกเซล (ช่วง HTML 1*1px) ถูกสร้างขึ้นด้วยสี RGBA เริ่มต้นคงที่แบบสุ่ม (A=0=โปร่งใส)

 ให้ d = Date.now(); // ประทับเวลา 13 หลัก
 ให้ n = 100 // จำนวน 'พิกเซล' 
 ให้พิกเซล = ''

 สำหรับ (i=0; i<n; i++) {
    ให้ r = Math.floor(คณิตศาสตร์สุ่ม() * 256); 
    ให้ g = Math.floor(คณิตศาสตร์สุ่ม() * 256); 
    ให้ b = Math.floor(คณิตศาสตร์สุ่ม() * 256);
    ให้ c = 'rgba('+r+','+g+','+b+',0)'
    พิกเซล += '<span id="pix'+i+'" style="background-color:'+c+'"></span>'
 }

เมื่อเสร็จแล้ว เราจะสุ่มเปลี่ยนสีของแต่ละ 'พิกเซล' ทุกๆ 100 วินาที

 ให้ changeColor = setInterval(function(){
    สำหรับ (i=0; i<n; i++) {
        ให้ r = Math.floor(คณิตศาสตร์สุ่ม() * 256); 
        ให้ g = Math.floor(คณิตศาสตร์สุ่ม() * 256); 
        ให้ b = Math.floor(คณิตศาสตร์สุ่ม() * 256); 
        ให้ c = 'rgba('+r+','+g+','+b+',0)'
        document.getElementById('pix'+i).style.backgroundColor = ค
    }
 },10);

เมื่อผู้ใช้คลิกที่ 'ตกลง' ฟังก์ชันจะหยุดลง พิกเซลแบบสุ่มจะถูกกำหนดและพบค่า RGB

ให้ x = Math.floor(คณิตศาสตร์สุ่ม() * n); // 39
ให้ px = window.getComputedStyle(document.getElementById('pix'+x),null).backgroundColor
ให้ rgb = px.match(/\d+/g); // รูป 39 = [21,13,152]

จากนั้นเราคูณค่า RGB แต่ละค่าด้วย x * ปัจจัยสุ่ม [1 ถึง 5]:

ให้ r = rgb[0]*(x*Math.floor(สุ่มคณิตศาสตร์() * 5)+1), // 21 * 39 * 2 = 1638
    g = rgb[1]*(x*Math.floor(สุ่มคณิตศาสตร์() * 5)+1), // 13 * 39 * 1 = 507
    b = rgb[2]*(x*Math.floor(สุ่มคณิตศาสตร์() * 5)+1) // 152 * 39 * 4 = 23712

โดยการเพิ่ม x + ตัวจับเวลา + การแยกการประทับเวลาแบบสุ่มที่เราได้รับ:

ให้ t = Date.now()-d; // จับเวลาเมื่อคลิก
ให้ p = Math.floor(คณิตศาสตร์สุ่ม() * 4)+3;    
ให้ z = d.toString().substr(-p) // ค่า xx เวลาประทับล่าสุด (3->7)

ให้ val = x+''+r+g+b+''+t+z // 39 1368 507 23712 1348 55601

จากนั้นเราจะสุ่มผลลัพธ์แบบสุ่ม:

การสับเปลี่ยนฟังก์ชัน (a) {
  ให้ r = ก.ความยาว อุณหภูมิ แรนด์;
  ในขณะที่ (0 !== r) {
    แรนด์ = Math.floor(คณิตศาสตร์สุ่ม() * r);
    r -= 1;
    อุณหภูมิ = a[r];
    ก[r] = ก[แรนด์];
    a[แรนด์] = อุณหภูมิ;
  }
  คืน ก; // 39136850723712134855601 -> 25851963017738613021534
}

  การทดสอบ -> คอนโซล
  17:22:34 พิกเซล #39 = [21,13,152] 9348234523267751239843
  17:22:42 พิกเซล #39 = [21,13,152] 109715237240854257137
  17:23:02 พิกเซล #39 = [21,13,152] 100889146450039658553439

หากเราต้องการผลลัพธ์ที่ยาวขึ้น (50, 100 หลัก) เราสามารถสร้าง 500 'พิกเซล' และสุ่มเลือก 10 พิกเซลแทนที่จะเป็น 1 พิกเซล หรือเพิ่มค่าเอนโทรปี (การเคลื่อนไหวของเมาส์บนหน้าจอ : https://www.grc.com/r&d/js.htm) เป็นค่าที่ได้รับ คุณคิดอย่างไร?

Eugene Styer avatar
dz flag
จาก: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random: หมายเหตุ: Math.random() ไม่ได้ให้ตัวเลขสุ่มที่ปลอดภัยด้วยการเข้ารหัส อย่าใช้เพื่อสิ่งที่เกี่ยวข้องกับความปลอดภัย ใช้ Web Crypto API แทน และใช้เมธอด window.crypto.getRandomValues() อย่างแม่นยำยิ่งขึ้น
Maarten Bodewes avatar
in flag
ปัญหาของรูปแบบนี้คือ `Math.random()` ไม่ได้ระบุตัวเลขสุ่ม โดยปกติจะถูกสร้างขึ้นโดยใช้เมล็ด 32 บิตที่อาจคาดเดาได้ง่าย ดังนั้นอินพุตเดียวที่ดูเหมือนสุ่มทั้งหมดคือเวลาระหว่างการคำนวณเริ่มต้นและผู้ใช้กดปุ่ม [ตกลง] โอ้ และคุณใส่ `Date()` ซึ่งไม่ใช่การสุ่มเลย การสุ่มนี้ขึ้นอยู่กับระบบมากกว่าสิ่งอื่นใดที่ฉันคิด อย่างน้อยฉันก็คาดหวังว่าใครสักคนที่สามารถตั้งโปรแกรมสคริปต์เพื่อเริ่มการคำนวณ ณ เวลาใดเวลาหนึ่ง & แทบจะในทันทีที่สามารถบังคับให้มันไม่เป็นแบบสุ่ม
Maarten Bodewes avatar
in flag
[นี่จะเป็นการสุ่มมากกว่า](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
ph flag
การใช้พิกเซลสีไม่ได้ให้ฟังก์ชันใด ๆ ข้างต้นในการจัดเก็บค่าเหล่านั้นในอาร์เรย์
Score:1
ธง fr

คณิต.สุ่ม ไม่ใช่ PRNG ที่ปลอดภัยด้วยการเข้ารหัส ตัวอย่างเช่น Firefox ใช้ตัวสร้างที่ใช้ XorShift ซึ่งจะทำให้สถานะทั้งหมดรั่วไหลหลังจากการเรียกเพียงไม่กี่ครั้ง ดังนั้น คุณไม่ได้สร้างพิกเซลแบบสุ่มที่นี่จริงๆ คุณแค่เลือกค่าตามเมล็ดก่อนหน้าเดียวกัน

MDN อธิบาย ฟังก์ชัน Web Cryptography API สำหรับสร้างตัวเลขสุ่มที่ปลอดภัยด้วยการเข้ารหัส. หากคุณกำลังทำงานใน Node.js แทน มันจะมาพร้อมกับ ฟังก์ชันในตัวที่ทำสิ่งเดียวกัน. สิ่งเหล่านี้ได้รับการออกแบบมาเพื่อใช้ CSPRNG โดยปกติจะเป็นระบบที่คุณควรใช้เว้นแต่คุณจะแน่ใจว่าต้องการสิ่งอื่น เหมาะสำหรับความต้องการในการเข้ารหัสเกือบทั้งหมด และแนะนำให้ใช้ระบบ CSPRNG โดยนักเข้ารหัสส่วนใหญ่

หากคุณต้องการบางอย่างที่ทำซ้ำได้ คุณสามารถใช้บางอย่างเช่น ChaCha20 กับคีย์และ nonce ที่สร้างจากระบบ CSPRNG หรือ HMAC-DRBG ที่มี SHA-2 หรือ SHA-3 อย่างไรก็ตาม สิ่งนี้ไม่จำเป็นในสถานการณ์ส่วนใหญ่ และจะเป็นการดีกว่าหากเป็นไปได้เพื่อหลีกเลี่ยงการใช้การเข้ารหัสของคุณเองแทนการใช้งานที่รู้จักและเชื่อถือได้ ดังนั้นหากคุณต้องการสิ่งนี้ คุณควรใช้การใช้งานที่รู้จักจะดีกว่า

Wolden avatar
cn flag
ขอบคุณสำหรับคำตอบและความคิดเห็น ฉันเห็นด้วยกับจุดอ่อนของ Math.random แต่นอกเหนือจากตำแหน่งของหลักการแล้ว มันทำให้ผลลัพธ์เหล่านี้สามารถคาดเดาได้หรือไม่ ดังนั้นจึงไม่ปลอดภัย ถ้าเป็นเช่นนั้น ทำไม และอย่างไร? ขอบคุณสำหรับความช่วยเหลือในการทำความเข้าใจ ฉันไม่มีอะไรนอกจากผู้เริ่มต้นในการเข้ารหัส ;-)
Wolden avatar
cn flag
ดังที่แสดงใน 3 บรรทัดสุดท้ายของฉัน (tests->console) เมื่อฟังก์ชันหยุดทำงาน จะมีการกำหนดการประทับเวลาและพิกเซล ฉันคลิกหลายครั้งบนปุ่มตกลงจนกระทั่งฉันพบผลลัพธ์ 3 รายการสำหรับพิกเซลเดียวกัน (#39): ด้วยค่า RGB เดียวกัน ฉันได้รับผลลัพธ์ที่แตกต่างกันมาก 3 รายการ สามารถคาดเดาได้หรือไม่ (เช่น ใน 'รายการผลลัพธ์ที่เป็นไปได้' ที่คาดเดาได้)
bk2204 avatar
fr flag
พวกเขาอาจคาดเดาได้เพียงพอว่าวิธีการนี้อาจใช้กำลังดุร้าย เพียงเพราะมัน "ดูสุ่ม" ไม่ได้หมายความว่าจะไม่สามารถคาดเดาได้ ฉันจะไม่ทำการวิเคราะห์การเข้ารหัสเต็มรูปแบบในแนวทางนี้ เพราะฉันคิดว่าการใช้ระบบ CSPRNG นั้นดีกว่าอย่างเห็นได้ชัดและเป็นทางเลือกที่สมเหตุสมผล แต่ถ้าคุณใช้ `Math.random` เป็นแหล่งสุ่มที่คุณต้องการ CSPRNG ฉันจะ ขอ CVE กับซอฟต์แวร์ของคุณ
Wolden avatar
cn flag
ขอบคุณสำหรับคำอธิบาย :-)
Score:0
ธง cn

ฉันใช้ฟังก์ชัน Math.random() มากกว่า 6 ครั้ง หนึ่งครั้งเพื่อรับค่า 0->255 (r,g,b) หนึ่งครั้งเพื่อรับค่า 0->100 (จำนวนพิกเซล) และบางส่วนเพื่อ รับค่าที่น้อยลง (เช่น 3->5 สำหรับการประทับเวลา)

ตอนนี้ค่า 0->255 (r,g,b) ถูกนำมาจาก

    ให้ rand = ใหม่ Uint8Array(3); // 3 ค่า 0 -> 255
    window.crypto.getRandomValues(แรนด์);
    ให้ r = แรนด์ [0]; 
    ให้ g = แรนด์ [1]; 
    ให้ b = แรนด์ [2];

และค่า 0->100 (จำนวนพิกเซล) จาก

    ให้ pix = ใหม่ Uint8Array(1);
    window.crypto.getRandomValues(พิกเซล);
    ให้ v = Math.floor(pix[0]/2.55); // ค่า 0->100

เมื่อฉันได้แทนที่ฟังก์ชัน Math.random() ทั้งหมดด้วยการใช้งานใหม่เหล่านี้แล้ว คุณคิดว่ามีความปลอดภัยและเชื่อถือได้มากขึ้น/ทนต่อการโจมตีหรือไม่

คำถามนี้เป็นภาษาอื่นๆ:

โพสต์คำตอบ

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