การป้องกันการแทรก SQL ใน Node.js


88

เป็นไปได้หรือไม่ที่จะป้องกันการแทรก SQL ใน Node.js (โดยเฉพาะอย่างยิ่งกับโมดูล) ในลักษณะเดียวกับที่ PHP มีคำสั่งที่เตรียมไว้ซึ่งป้องกันพวกเขา

ถ้าเป็นเช่นนั้นอย่างไร? หากไม่เป็นเช่นนั้นตัวอย่างใดบ้างที่อาจข้ามรหัสที่ฉันให้ไว้ (ดูด้านล่าง)


บริบทบางส่วน:

ฉันกำลังสร้างเว็บแอปพลิเคชันที่มี back-end stack ซึ่งประกอบด้วย Node.js + MySql โดยใช้โมดูลnode-mysql จากมุมมองด้านการใช้งานโมดูลนี้ยอดเยี่ยมมาก แต่ยังไม่ได้ใช้บางสิ่งที่คล้ายกับคำสั่งเตรียมการของ PHP (แม้ว่าฉันจะทราบว่าเป็นสิ่งที่ต้องทำ )

จากความเข้าใจของฉันการใช้ PHP ของคำสั่งที่เตรียมไว้เหนือสิ่งอื่นใดช่วยอย่างมากในการป้องกันการแทรก SQL อย่างไรก็ตามฉันกังวลว่าแอป node.js ของฉันอาจเปิดรับการโจมตีที่คล้ายกันแม้ว่าจะมีการหลีกเลี่ยงสตริงที่ให้ไว้โดยค่าเริ่มต้นก็ตาม (ดังในข้อมูลโค้ดด้านล่าง)

node-mysql ดูเหมือนจะเป็นตัวเชื่อมต่อ mysql ที่ได้รับความนิยมมากที่สุดสำหรับ node.js ดังนั้นฉันจึงสงสัยว่าคนอื่นอาจทำอะไร (ถ้ามี) เพื่ออธิบายปัญหานี้ - หรือแม้ว่าจะเป็นปัญหากับ node.js ที่จะเริ่มต้นด้วย (ไม่แน่ใจว่าจะไม่เป็นเช่นไรเนื่องจากอินพุตฝั่งผู้ใช้ / ไคลเอ็นต์เกี่ยวข้อง)

ฉันควรเปลี่ยนไปใช้node-mysql-nativeในขณะนี้เนื่องจากมีคำสั่งที่เตรียมไว้หรือไม่ ฉันลังเลที่จะทำสิ่งนี้เพราะดูเหมือนว่าจะไม่ทำงานเท่า node-mysql (แม้ว่านั่นอาจหมายความว่ามันเสร็จสมบูรณ์แล้วก็ตาม)

นี่คือตัวอย่างของรหัสการลงทะเบียนผู้ใช้ซึ่งใช้โมดูลเจลทำความสะอาดพร้อมกับไวยากรณ์คำสั่งคล้ายคำสั่งที่เตรียมไว้ของ node-mysql (ซึ่งตามที่ฉันได้กล่าวไว้ข้างต้นจะทำให้อักขระหลบหนี) เพื่อป้องกันการเขียนสคริปต์ข้ามไซต์และการแทรก sql ตามลำดับ:

// Prevent xss
var clean_user = sanitizer.sanitize(username);

// assume password is hashed already
var post = {Username: clean_user, Password: hash};

// This just uses connection.escape() underneath
var query = connection.query('INSERT INTO users SET ?', post,
   function(err, results)
   {
       // Can a Sql injection happen here?
   });

คำตอบ:


60

node-mysqlห้องสมุดดำเนินการโดยอัตโนมัติ Escape ที่เมื่อนำมาใช้ในขณะที่คุณกำลังทำอยู่แล้ว ดูhttps://github.com/felixge/node-mysql#escaping-query-values


3
ดังที่ได้กล่าวไว้ในโพสต์ของฉันฉันทราบว่าไลบรารีหลีกเลี่ยงอักขระ แต่ฉันกังวลมากขึ้นเกี่ยวกับผลกระทบด้านความปลอดภัยหากฉันไม่เปลี่ยนไปใช้ไลบรารีที่ใช้คำสั่งที่เตรียมไว้นั่นคือมีการแทรก SQL ที่สามารถเกิดขึ้นได้กับสิ่งที่ ฉันกำลังทำอยู่?
funseiki

2
การหลีกเลี่ยงอักขระป้องกันการแทรก SQL การแทรกจะเกิดขึ้นเมื่ออักขระไม่ได้ใช้ Escape และผู้ใช้ที่เป็นอันตรายสามารถใช้ประโยชน์จากสิ่งนี้เพื่อปิดการสืบค้นและเริ่มต้นใหม่เพื่อพูดวางตารางหรือแทรกระเบียนปลอม ด้วยอักขระที่ไม่ได้รับการยกเว้นจะเป็นไปไม่ได้ Wikipediaมีข้อมูลเพิ่มเติมเกี่ยวกับ SQL Injection
Michael Pratt

4
แต่มันป้องกันการฉีด SQL ทั้งหมดหรือไม่? คำตอบนี้ไม่แนะนำ (อย่างน้อยสำหรับ PHP + MySQL) และหมายความว่า Prepared Statements ของ PHP ทำ อีกครั้งนี่อยู่ในบริบทของ PHP
funseiki

1
ตามลิงค์ของคุณซึ่งใช้งานได้กับ MySQL เวอร์ชันที่ล้าสมัยเท่านั้น ฉันไม่รู้ว่าการโจมตีนั้นทำงานบน Node หรือไม่ แต่ดูเหมือนว่าจะเกี่ยวข้องกับช่องโหว่ของ PHP ที่เฉพาะเจาะจงมากดังนั้นความรู้สึกในใจของฉันจึงไม่ใช่ ฉันไม่ได้บอกว่าไม่มีช่องโหว่ใน node-mysql แต่มันถูกใช้ในสภาพแวดล้อมการผลิตจำนวนมากอยู่แล้ว หากคุณยังคงกังวลเกี่ยวกับการแทรก SQL ฉันขอแนะนำให้กัดสัญลักษณ์แสดงหัวข้อย่อยและลองใช้บางอย่างเช่น MongoDB - ไม่สามารถทำการฉีด SQL ได้หากคุณไม่ได้ใช้ SQL
Michael Pratt

1
ดูเหมือนอย่างนั้นและเส้นทาง MongoDB เป็นจุดที่ดี - แม้ว่าการออกแบบในปัจจุบันจะให้ยืมตัวเองกับสคีมาเชิงสัมพันธ์ได้เป็นอย่างดี ฉันจะรอดูว่ามีใครมีข้อมูลเชิงลึกเกี่ยวกับช่องโหว่ด้านความปลอดภัยหรือไม่มิฉะนั้นดูเหมือนว่าฉันจะเห็นด้วยกับ node-mysql เท่านั้น
funseiki

12

ไลบรารีมีส่วนใน readme เกี่ยวกับการหลบหนี มัน Javascript พื้นเมืองดังนั้นผมจึงไม่แนะนำให้เปลี่ยนไปใช้โหนด MySQL พื้นเมือง เอกสารระบุแนวทางเหล่านี้สำหรับการหลบหนี:

แก้ไข: node-mysql-nativeยังเป็นโซลูชัน Pure-Javascript

  • ตัวเลขไม่ถูกแตะต้อง
  • บูลีนถูกแปลงเป็นtrue/ falseสตริง
  • อ็อบเจ็กต์วันที่ถูกแปลงเป็นYYYY-mm-dd HH:ii:ssสตริง
  • บัฟเฟอร์จะถูกแปลงเป็นสตริงเลขฐานสิบหกเช่น X'0fa5'
  • สตริงหนีได้อย่างปลอดภัย
  • อาร์เรย์จะกลายเป็นรายการเช่น['a', 'b']เปลี่ยนเป็น'a', 'b'
  • อาร์เรย์ที่ซ้อนกันจะเปลี่ยนเป็นรายการที่จัดกลุ่ม (สำหรับการแทรกจำนวนมาก) เช่น[['a', 'b'], ['c', 'd']]เปลี่ยนเป็น('a', 'b'), ('c', 'd')
  • วัตถุจะกลายเป็นkey = 'val'คู่ วัตถุที่ซ้อนกันจะถูกส่งไปยังสตริง
  • undefined/ nullถูกแปลงเป็นไฟล์NULL
  • NaN/ Infinityถูกทิ้งไว้ตามที่เป็นอยู่ MySQL ไม่รองรับสิ่งเหล่านี้และการพยายามแทรกเป็นค่าจะทำให้เกิดข้อผิดพลาด MySQL จนกว่าจะใช้การสนับสนุน

สิ่งนี้ช่วยให้คุณทำสิ่งต่างๆดังนี้:

var userId = 5;
var query = connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
  //query.sql returns SELECT * FROM users WHERE id = '5'
});

เช่นเดียวกับสิ่งนี้:

var post  = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) {
  //query.sql returns INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
});

นอกเหนือจากฟังก์ชันเหล่านี้คุณยังสามารถใช้ฟังก์ชัน Escape:

connection.escape(query);
mysql.escape(query);

ในการหลีกเลี่ยงตัวระบุการค้นหา:

mysql.escapeId(identifier);

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

จากมุมมองด้านการใช้งานโมดูลนี้ยอดเยี่ยมมาก แต่ยังไม่ได้ใช้บางสิ่งที่คล้ายกับคำสั่งเตรียมการของ PHP

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

connection.config.queryFormat = function (query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      return this.escape(values[key]);
    }
    return txt;
  }.bind(this));
};

สิ่งนี้จะเปลี่ยนรูปแบบการสืบค้นของการเชื่อมต่อเพื่อให้คุณสามารถใช้คิวรีดังนี้:

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");

ขอบคุณสำหรับการตอบกลับ - ฉันตระหนักถึงรูปแบบที่เหมือนเตรียมไว้ อย่างไรก็ตามภายใต้ตัวละครกำลังหลบหนี ดู: "แต่ก็จริงๆเพียงแค่ใช้ connection.escape เดียวกัน ()" เท่าที่ไม่ใช้ node-mysql-native นี่คือสิ่งที่ฉันกำลังดิ้นรน หาก node-mysql-native ใช้คำสั่งที่เตรียมไว้และการนำไปใช้ป้องกันการแทรก SQL ฉันไม่ควรทำการสลับจนกว่า node-mysql จะมีหรือไม่
funseiki

เป็นคำถามแบบไก่กับไข่ ฉันไม่ได้พัฒนาไดรเวอร์ของฉันอย่างจริงจังเพราะคนส่วนใหญ่ใช้ @ felixge ฉันอาจจะพยายามหาเวลาพอร์ทงบที่เตรียมไว้ไปยัง node-mysql เนื่องจากมันให้ประโยชน์ด้านประสิทธิภาพบางอย่าง (และอาจทำให้การฉีด sql ยากขึ้น) อย่าลังเลที่จะแสดงความคิดเห็น / โพสต์ปัญหาหากคุณตัดสินใจที่จะไป
Andrey Sidorov

1
@funseiki ฉันแน่ใจว่าข้อความที่เตรียมไว้จะเป็นทางออกที่ดีที่สุด แต่ฉันมั่นใจมากว่าการหลบหนีจะป้องกันการแทรก SQL เนื่องจากตัวโมดูลได้รับการสนับสนุนโดย Joyent โมดูลจึงทำงานและได้รับการตรวจสอบอย่างละเอียด หากโมดูลนี้ไม่พร้อมสำหรับการผลิตฉันไม่คิดว่าโมดูลจะมีการดาวน์โหลดเฉลี่ย 1,000 ครั้ง / วันในเดือนที่แล้ว โปรดทราบว่า node-mysql-native มีอายุ 6 เดือนนับตั้งแต่ได้รับการพัฒนาครั้งล่าสุดและ node-mysql มีการใช้งานมากโดยมีหลายคนที่ทำงานกับมัน
hexacyanide

@AndreySidorov ขอบคุณสำหรับความคิดเห็น - ถ้าฉันพยายามจัดการกับมันฉันจะโพสต์อัปเดต ฉันไม่คิดว่ามันจะเร็ว ๆ นี้เพราะมันดูเหมือนว่ามันจะเป็นสัตว์ร้ายที่จัดการได้ง่าย ๆ (จะต้องใช้การค้นคว้ามากกว่าที่ฉันมีในตอนนี้) ขอบคุณที่สร้างไดรเวอร์นั้น - พวกคุณคือเหตุผลที่ Node.js ทำให้แอปทำงานได้อย่างรวดเร็ว
funseiki

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

11

ฉันรู้ว่านี่เป็นโพสต์ที่เก่ากว่า แต่ดูเหมือนว่าจะไม่มีการทำเครื่องหมายคำตอบดังนั้นฉันจะโยนสิ่งนี้ออกไป

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

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

  1. เพื่อให้ทันกับช่องโหว่คุณจะต้องติดตามรายชื่ออีเมลฟอรัม IRC และการสนทนาอื่น ๆ ที่เกี่ยวข้องกับการแฮ็ก PRO: บ่อยครั้งคุณจะตระหนักถึงปัญหาที่อาจเกิดขึ้นภายในไลบรารีก่อนที่ผู้ขายจะได้รับการแจ้งเตือนหรือออกโปรแกรมแก้ไข / แก้ไขเพื่อแก้ไขช่องทางที่อาจเกิดขึ้นจากการโจมตีซอฟต์แวร์ของพวกเขา ข้อเสีย: อาจใช้เวลานานและใช้ทรัพยากรมาก หากคุณกำหนดเส้นทางบอทโดยใช้ฟีด RSS การแยกวิเคราะห์บันทึก (บันทึกการแชท IRC) และหรือเว็บสแครปเปอร์โดยใช้วลีสำคัญ (ในกรณีนี้คือ node-mysql-native) และการแจ้งเตือนจะช่วยลดเวลาที่ใช้ในการหมุนทรัพยากรเหล่านี้

  2. สร้าง fuzzer ใช้fuzzerหรือกรอบช่องโหว่อื่น ๆ เช่นmetasploit , sqlMapเป็นต้นเพื่อช่วยทดสอบปัญหาที่ผู้ขายอาจไม่ได้มองหา PRO: นี่สามารถพิสูจน์ได้ว่าเป็นวิธีการยิงที่แน่นอนในการตรวจสอบให้อยู่ในระดับที่ยอมรับได้ว่าโมดูล / ซอฟต์แวร์ที่คุณใช้นั้นปลอดภัยหรือไม่สำหรับการเข้าถึงของสาธารณะ ข้อเสีย: สิ่งนี้ใช้เวลานานและมีค่าใช้จ่ายสูง ปัญหาอื่น ๆ จะเกิดจากผลบวกที่ผิดพลาดรวมทั้งการทบทวนผลลัพธ์ที่ไม่มีการศึกษาซึ่งปัญหาอยู่ แต่ไม่ได้สังเกตเห็น

ความปลอดภัยจริงๆและการรักษาความปลอดภัยของแอปพลิเคชันโดยทั่วไปอาจใช้เวลานานและใช้ทรัพยากรมาก สิ่งหนึ่งที่ผู้จัดการมักจะใช้คือสูตรในการกำหนดประสิทธิผลด้านต้นทุน (กำลังคนทรัพยากรเวลาการจ่ายเงิน ฯลฯ ) ของการดำเนินการสองตัวเลือกข้างต้น

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


3

ฉันรู้ว่าคำถามนี้เก่า แต่สำหรับทุกคนที่สนใจ Mysql-native นั้นล้าสมัยแล้วดังนั้นจึงกลายเป็นMySQL2ซึ่งเป็นโมดูลใหม่ที่สร้างขึ้นด้วยความช่วยเหลือของทีมโมดูล MySQL ดั้งเดิม โมดูลนี้มีคุณสมบัติมากกว่าและฉันคิดว่ามันมีสิ่งที่คุณต้องการเนื่องจากได้เตรียมงบไว้ (โดยใช้. execute ()) เช่นใน PHP เพื่อความปลอดภัยที่มากขึ้น

นอกจากนี้ยังมีการใช้งานมาก (การเปลี่ยนแปลงครั้งล่าสุดคือจาก 2-1 วัน) ฉันไม่ได้ลองมาก่อน แต่ฉันคิดว่าเป็นสิ่งที่คุณต้องการและอื่น ๆ


-1

วิธีที่ง่ายที่สุดคือจัดการการโต้ตอบฐานข้อมูลทั้งหมดของคุณในโมดูลของตัวเองที่คุณส่งออกไปยังเส้นทางของคุณ หากเส้นทางของคุณไม่มีบริบทของฐานข้อมูล SQL จะไม่สามารถสัมผัสได้อยู่ดี


นั่นไม่ได้ตอบคำถามของ OP เกี่ยวกับวิธีการฆ่าเชื้อ
Christopher
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.