ช่องโหว่การเล่นซ้ำลายเซ็นในสัญญาอัจฉริยะ | บล็อกการตรวจสอบ

Nov 30 2022
เคล็ดลับที่เป็นประโยชน์คือการเซ็นข้อความนอกเครือข่ายและมีสัญญาที่ต้องการลายเซ็นนั้นก่อนดำเนินการ ตัวอย่างเช่น เทคนิคนี้ใช้เพื่อ: -- ลดจำนวนธุรกรรมในธุรกรรมที่ไม่มีก๊าซแบบลูกโซ่ ซึ่งเรียกว่าธุรกรรมเมตา มาดูกันว่าเรากำลังพูดถึงอะไร บล็อกเชนพึ่งพาลายเซ็นเข้ารหัสเป็นอย่างมาก

เคล็ดลับที่เป็นประโยชน์คือการเซ็นข้อความนอกเครือข่ายและมีสัญญาที่ต้องการลายเซ็นนั้นก่อนดำเนินการ

ตัวอย่างเช่น เทคนิคนี้ใช้เพื่อ: -
-ลดจำนวนธุรกรรมในห่วงโซ่
- ธุรกรรมที่ไม่มีก๊าซ เรียกว่า
meta transaction

มาดูกันว่าเรากำลังพูดถึงอะไร

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

ลายเซ็นดิจิทัลมักได้รับการตรวจสอบโดยตรงในสัญญาอัจฉริยะของ Ethereum ทำให้ผู้ตรวจสอบอย่างน้อยหนึ่งรายสามารถอนุญาตการดำเนินการโดยการส่งลายเซ็นออฟไลน์ ( หรือแม้แต่ลายเซ็นที่สร้างโดยสัญญาอัจฉริยะอื่น )

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

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

ตัวอย่างเช่น: -
ติดตามแฮชข้อความที่ประมวลผลทั้งหมดและอนุญาตให้ประมวลผลแฮชข้อความใหม่เท่านั้น ผู้ใช้ที่ประสงค์ร้ายสามารถโจมตีสัญญาที่ขาดการควบคุมดังกล่าว และรับแฮชข้อความที่ส่งมาจากผู้ใช้รายอื่นและประมวลผลหลายครั้ง

ลายเซ็นดิจิทัลแบบเข้ารหัส

ลายเซ็นดิจิทัลเป็นรหัสสาธารณะดั้งเดิมของการรับรองความถูกต้องของข้อความ ในโลกทางกายภาพ ลายเซ็นที่เขียนด้วยลายมือมักใช้กับข้อความที่เขียนด้วยลายมือหรือข้อความที่พิมพ์ ใช้เพื่อผูกมัดผู้ลงนามกับข้อความ

ลายเซ็นดิจิทัลคือค่าการเข้ารหัสที่สร้างขึ้นโดยข้อมูลและรหัสลับที่ผู้ลงนามเท่านั้นที่รู้จัก

รูปแบบของลายเซ็นดิจิทัล

ขั้นตอนทั้งหมดได้รับการอธิบายอย่างละเอียดในประเด็นต่อไปนี้:

ที่มาของภาพ : วิกิพีเดีย
  • ผู้ใช้แต่ละรายของโครงร่างนี้มีชุดของคีย์สาธารณะและส่วนตัว
  • คู่คีย์ที่ใช้สำหรับการเข้ารหัส/ถอดรหัสและการเซ็นชื่อ/การตรวจสอบมักจะแตกต่างกัน รหัสสาธารณะเรียกว่ารหัสการตรวจสอบและรหัสส่วนตัวเรียกว่ารหัสลายเซ็น
  • ข้อมูลถูกส่งไปยังฟังก์ชันแฮชโดยผู้ลงนามซึ่งสร้างแฮช
  • อัลกอริทึมลายเซ็นจะสร้างลายเซ็นดิจิทัลบนแฮชที่ให้มาโดยใช้ค่าแฮชและคีย์ลายเซ็น ข้อมูลจะได้รับลายเซ็นและทั้งสองจะถูกส่งไปยังผู้ตรวจสอบในภายหลัง
  • อัลกอริทึมการตรวจสอบถูกป้อนโดยผู้ตรวจสอบพร้อมกับลายเซ็นดิจิทัลและรหัสการตรวจสอบ ผลลัพธ์ของอัลกอริทึมการตรวจสอบเป็นสิ่งที่มีประโยชน์ สำหรับข้อมูลที่ได้รับ ผู้ตรวจสอบยังใช้อัลกอริทึมแฮชเดียวกันเพื่อสร้างค่าแฮช
  • ค่าแฮชนี้และผลลัพธ์ของกระบวนการตรวจสอบจะถูกเปรียบเทียบเพื่อการตรวจสอบ ตัวตรวจสอบจะตัดสินว่าลายเซ็นดิจิทัลนั้นถูกต้องตามกฎหมายหรือไม่โดยพิจารณาจากผลลัพธ์ของการเปรียบเทียบ
  • ไม่มีใครสามารถใช้คีย์ "ส่วนตัว" ของผู้ลงนามเพื่อสร้างลายเซ็นดิจิทัล ดังนั้นผู้ลงนามจึงไม่สามารถถอนลายเซ็นข้อมูลของตนได้ในภายหลัง

ชั้นโปรโตคอล

เฉพาะธุรกรรมที่มีลายเซ็นที่ถูกต้องเท่านั้นที่จะรวมอยู่ในบล็อกใหม่ ต้องขอบคุณ เครือ ข่ายEthereum สำหรับการทำธุรกรรม ข้อเสนอนี้มีแอตทริบิวต์ความปลอดภัยดังต่อไปนี้:

  • การ รับรองความถูกต้อง : โหนด Ethereum ใช้ลายเซ็นเพื่อยืนยันว่าบุคคลที่ลงนามธุรกรรมเป็นเจ้าของคีย์ส่วนตัวที่เชื่อมต่อกับที่อยู่สาธารณะ ดังนั้นผู้พัฒนาอาจมั่นใจได้ว่า msg.sender เป็นของแท้
  • ความสมบูรณ์ : ความสมบูรณ์เป็นเงื่อนไขที่ธุรกรรมจะไม่เปลี่ยนแปลงหลังจากลงนามแล้ว มิฉะนั้นลายมือชื่อจะเป็นโมฆะ
  • การไม่ปฏิเสธ:ลายเซ็นของการทำธุรกรรมและการเปลี่ยนแปลงสถานะใด ๆ ที่ทำโดยฝ่ายที่ลงนามซึ่งครอบครองคีย์ส่วนตัวไม่สามารถโต้แย้งได้ รหัสส่วนตัวเป็นของที่อยู่สาธารณะที่แสดงอยู่ในช่องจาก

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

ตัวอย่างโค้ด

ลองตรวจสอบข้อผิดพลาด

function unlock(
  address _to,
  uint256 _amount,
  uint8[] _v,
  bytes32[] _r,
  bytes32[] _s
)
  external
{
  require(_v.length >= 20);
  bytes32 hashData = keccak256(_to, _amount);
  for (uint i = 0; i < _v.length; i++) {
    address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
    require(_isValidator(recAddr));
  }
  to.transfer(_amount);
}

ข้อความที่ลงนามโดยผู้ตรวจสอบความถูกต้องโดยใช้เทคนิค ECDSA คือปัญหาของรหัสดังกล่าว ที่อยู่ผู้รับและเงินที่ต้องการเป็นข้อมูลเดียวในข้อความ ไม่มีอะไรในข้อความที่จะหลีกเลี่ยงการใช้ลายเซ็นเดียวกันมากกว่าหนึ่งครั้ง พิจารณากรณีต่อไปนี้:

  • Sam โอน 2,000 ETH จากเครือข่ายที่เชื่อมโยงกลับไปยัง Ethereum chain โดยใช้สกุลเงินจำนวนเท่ากัน
  • การประมวลผลธุรกรรมข้ามบล็อกเชนนี้คือ Tom ผู้ถ่ายทอด ในการปลด 2,000 ETH จากสัญญาและส่งไปยัง Sam เขารวบรวมลายเซ็นของผู้ตรวจสอบความถูกต้องที่จำเป็น ล็อคจำนวนที่ถูกต้องบนเชนที่เชื่อมต่อ จากนั้นใช้ฟังก์ชั่นปลดล็อค
  • ใน blockchain ธุรกรรมที่มีอาร์เรย์ของค่าลายเซ็นจะถูกมองเห็นโดยทุกคน
  • ตอนนี้ Sam ได้คัดลอกอาร์เรย์ลายเซ็นแล้ว เขาสามารถส่งการเรียกปลดล็อคได้อย่างอิสระ กระบวนการปลดล็อกจะสำเร็จอีกครั้ง ส่งผลให้มีการโอน 2,000 ETH ให้กับแซม
  • แซมสามารถดำเนินการในลักษณะนี้ต่อไปได้จนกว่าสัญญาจะหมดลง

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

ลงนามใน ข้อความnonceและที่อยู่ของสัญญา

public uint256 nonce;
function unlock(
  address _to,
  uint256 _amount, 
  uint256 _nonce,
  uint8[] _v,
  bytes32[] _r,
  bytes32[] _s
)
  external
{
  require(_v.length >= 20);
  require(_nonce == nonce++);
  bytes32 hashData = keccak256(_to, _amount, _nonce);
  for (uint i = 0; i < _v.length; i++) {
    address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
    require(_isValidator(recAddr));
  }
  to.transfer(_amount);
}

เพื่อป้องกันการโจมตีซ้ำลายเซ็น ให้พิจารณาคำแนะนำต่อไปนี้:

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

ลายเซ็นที่ไม่ซ้ำสามารถเล่นซ้ำได้ในหลายสถานการณ์ ดังตัวอย่างด้านบน เพื่อหลีกเลี่ยงการโจมตีซ้ำ ในสถานการณ์ส่วนใหญ่สิ่งสำคัญคือต้องแน่ใจว่าลายเซ็นตรงกันโดยเฉพาะกับการโทรแต่ละครั้ง นอกจากนี้ ด้วยเหตุนี้ nonce จึงรวมอยู่ในธุรกรรม Ethereum ทุกรายการ

อ้างอิง: -

https://solidity-by-example.org/hacks/signature-replay/
https://blog.finxter.com/smart-contract-replay-attack-solidity/
https://swcregistry.io/docs/SWC-121

เร่งมือกับ web3 Security!!! เชื่อมต่อกับเรา!!!

BlockAudit :- ทำไมเรา??
BlockAuditมีทรัพยากรและความรู้ในการสร้างโซลูชันความปลอดภัยทางไซเบอร์ที่ประหยัดเงินได้หลายล้านดอลลาร์
ลิงค์ดิน | เว็บไซต์ | ทวิตเตอร์