Ngăn chặn việc đưa vào SQL trong Node.js


86

Có thể ngăn chặn việc đưa SQL vào Node.js (tốt nhất là với một mô-đun) giống như cách mà PHP có các Câu lệnh chuẩn bị bảo vệ chống lại chúng không.

Nếu vậy, làm thế nào? Nếu không, một số ví dụ có thể bỏ qua mã tôi đã cung cấp là gì (xem bên dưới).


Một số bối cảnh:

Tôi đang tạo một ứng dụng web với ngăn xếp back-end bao gồm Node.js + MySql bằng cách sử dụng mô-đun node-mysql . Từ góc độ khả năng sử dụng, các mô-đun là rất tốt, nhưng nó vẫn chưa được thực hiện một cái gì đó giống như PHP chuẩn bị phát biểu (mặc dù tôi biết nó là trên todo ).

Theo hiểu biết của tôi, việc thực hiện các câu lệnh chuẩn bị của PHP, trong số những thứ khác, đã giúp rất nhiều trong việc ngăn chặn việc tiêm SQL. Tuy nhiên, tôi lo lắng rằng ứng dụng node.js của tôi có thể bị tấn công tương tự, ngay cả khi thoát chuỗi được cung cấp theo mặc định (như trong đoạn mã bên dưới).

node-mysql dường như là trình kết nối mysql phổ biến nhất cho node.js, vì vậy tôi đã tự hỏi những người khác có thể đang làm gì (nếu có) để giải thích cho vấn đề này - hoặc nếu nó là một vấn đề với node.js để bắt đầu (không chắc điều này sẽ như thế nào, vì đầu vào phía người dùng / máy khách có liên quan).

Tôi có nên chuyển sang node-mysql-native trong lúc này không, vì nó cung cấp các câu lệnh đã chuẩn bị sẵn? Tôi do dự khi làm điều này, bởi vì nó dường như không hoạt động như node-mysql (mặc dù điều đó có thể chỉ có nghĩa là nó đã hoàn thành).

Dưới đây là một đoạn mã đăng ký người dùng, sử dụng mô-đun sanitizer , cùng với cú pháp giống câu lệnh đã chuẩn bị sẵn của node-mysql (như tôi đã đề cập ở trên, không thoát ký tự), để ngăn chặn việc tạo tập lệnh trang web và chèn sql tương ứng:

// 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?
   });

Câu trả lời:


59

Các node-mysqlthư viện tự động thực hiện thoát khi sử dụng như bạn đã làm. Xem https://github.com/felixge/node-mysql#escaping-query-values


3
Như đã đề cập trong bài đăng của tôi, tôi biết rằng thư viện thoát các ký tự, nhưng tôi lo lắng hơn về các tác động bảo mật nếu tôi không chuyển sang thư viện đã triển khai các câu lệnh đã chuẩn bị sẵn, tức là liệu có sự chèn SQL có thể xảy ra với những gì Tôi hiện đang làm gì?
funseiki

2
Việc thoát ký tự ngăn chặn việc đưa vào SQL. Việc tiêm xảy ra khi các ký tự không được thoát và những người dùng độc hại có thể khai thác điều này để đóng truy vấn và bắt đầu một truy vấn mới, chẳng hạn như thả bảng hoặc chèn một bản ghi giả. Với các ký tự thoát, điều này là không thể. Wikipedia có một số thông tin bổ sung về SQL Injection.
Michael Pratt

4
Nhưng nó có ngăn chặn tất cả các lần tiêm SQL không? Câu trả lời này gợi ý là không (ít nhất là đối với PHP + MySQL) và ngụ ý rằng các Câu lệnh chuẩn bị của PHP làm được. Một lần nữa, điều này là trong ngữ cảnh của PHP.
funseiki

1
Theo liên kết của bạn, điều đó chỉ hoạt động trên các phiên bản MySQL lỗi thời. Tôi không biết liệu cuộc tấn công cụ thể đó có hoạt động trên Node hay không, nhưng có vẻ như nó liên quan đến các lỗ hổng PHP rất cụ thể, vì vậy cảm giác ruột của tôi là không. Tôi không nói rằng hoàn toàn không có lỗ hổng nào trong node-mysql, nhưng nó đã được sử dụng trong rất nhiều môi trường sản xuất. Nếu bạn vẫn lo lắng về SQL injection, tôi khuyên bạn nên cắn viên đạn và thử một cái gì đó như MongoDB - không thể thực hiện SQL injection nếu bạn không sử dụng SQL.
Michael Pratt

1
Nó trông như vậy và tuyến MongoDB là một điểm tốt - mặc dù thiết kế hiện tại sẽ rất phù hợp với một lược đồ quan hệ. Tôi sẽ chờ đợi để xem có ai khác có cái nhìn sâu sắc về các lỗ hổng bảo mật - nếu không, nó có vẻ như sự đồng thuận là hướng chỉ gắn bó với nút-mysql
funseiki

12

Thư viện có một phần trong readme về việc thoát. Đó là Javascript-native, vì vậy tôi không khuyên bạn nên chuyển sang node-mysql-native . Tài liệu nêu rõ các nguyên tắc sau để thoát:

Chỉnh sửa: node-mysql-native cũng là một giải pháp Javascript thuần túy.

  • Các con số được giữ nguyên
  • Boolean được chuyển đổi thành true/ falsestring
  • Đối tượng ngày tháng được chuyển đổi thành YYYY-mm-dd HH:ii:sschuỗi
  • Bộ đệm được chuyển đổi thành chuỗi hex, ví dụ: X'0fa5'
  • Các dây được thoát ra ngoài an toàn
  • Mảng được chuyển thành danh sách, ví dụ: ['a', 'b']biến thành'a', 'b'
  • Các mảng lồng nhau được chuyển thành danh sách được nhóm lại (đối với chèn hàng loạt), ví dụ: [['a', 'b'], ['c', 'd']]biến thành('a', 'b'), ('c', 'd')
  • Các đối tượng được chuyển thành key = 'val'từng cặp. Các đối tượng lồng nhau được chuyển thành chuỗi.
  • undefined/ nullđược chuyển đổi thànhNULL
  • NaN/ Infinityđược để nguyên. MySQL không hỗ trợ những điều này và việc cố gắng chèn chúng dưới dạng giá trị sẽ gây ra lỗi MySQL cho đến khi chúng triển khai hỗ trợ.

Điều này cho phép bạn làm những việc như vậy:

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'
});

Cũng như điều này:

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'
});

Ngoài các chức năng đó, bạn cũng có thể sử dụng các chức năng thoát:

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

Để thoát mã nhận dạng truy vấn:

mysql.escapeId(identifier);

Và như một phản hồi cho nhận xét của bạn về các tuyên bố đã chuẩn bị:

Từ góc độ khả năng sử dụng, mô-đun này rất tuyệt, nhưng nó vẫn chưa triển khai một cái gì đó giống với các Câu lệnh chuẩn bị của PHP.

Các báo cáo được chuẩn bị trên todo danh sách cho kết nối này, nhưng mô-đun này ít nhất cho phép bạn chỉ định định dạng tùy chỉnh mà có thể rất giống với báo cáo được chuẩn bị. Đây là một ví dụ từ 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));
};

Điều này thay đổi định dạng truy vấn của kết nối để bạn có thể sử dụng các truy vấn như sau:

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

Cảm ơn bạn đã phản hồi - Tôi biết phong cách giống như đã chuẩn bị. Tuy nhiên, bên dưới, các ký tự đang được thoát. Hãy xem: "Tuy nhiên, nó thực sự chỉ sử dụng cùng một kết nối.escape ()" . Về việc không sử dụng node-mysql-native: đây là điều tôi đang gặp khó khăn. Nếu node-mysql-native triển khai các câu lệnh đã chuẩn bị sẵn và các triển khai của nó ngăn chặn việc đưa SQL vào, tôi có nên thực hiện chuyển đổi cho đến khi node-mysql có chúng không?
funseiki

Đó là một câu hỏi về con gà và quả trứng. Tôi không tích cực phát triển trình điều khiển của mình bởi vì hầu hết mọi người sử dụng @ felixge, tôi có thể sẽ cố gắng tìm chút thời gian để chuyển các câu lệnh đã chuẩn bị sang node-mysql vì nó thực sự mang lại một số lợi ích về hiệu suất (và có khả năng khiến việc tiêm sql khó hơn). Cảm thấy tự do để bình luận / bài vấn đề nếu bạn quyết định để cho nó một đi
Andrey Sidorov

1
@funseiki Tôi chắc chắn rằng các câu lệnh chuẩn bị sẵn sẽ là giải pháp tốt nhất, nhưng tôi rất chắc chắn rằng việc thoát sẽ ngăn chặn việc tiêm SQL. Vì bản thân mô-đun được hỗ trợ bởi Joyent, nên mô-đun đang hoạt động và rõ ràng là đã được kiểm tra kỹ lưỡng. Nếu mô-đun này chưa sẵn sàng để sản xuất, thì tôi không nghĩ rằng mô-đun sẽ có trung bình 1000 lượt tải xuống / ngày vào tháng trước. Lưu ý rằng node-mysql-native là 6 tháng kể từ khi nó được phát triển lần cuối và node-mysql đang hoạt động rất tích cực, với nhiều người làm việc trên nó.
hexacyanide

@AndreySidorov Cảm ơn bạn đã nhận xét - nếu tôi cố gắng giải quyết nó, tôi sẽ đăng một bản cập nhật. Tuy nhiên, tôi không nghĩ nó sẽ sớm xảy ra vì có vẻ như nó không phải là một con quái vật dễ xử lý (sẽ cần nhiều nghiên cứu hơn so với thời gian hiện tại của tôi). Cũng nhờ để làm tài xế đó - các bạn là những lý do Node.js làm cho nó dễ dàng để có được các ứng dụng chạy nhanh
funseiki

@hexacyanide Vì node-mysql rất phổ biến nên tôi hy vọng có thể nhận được phản hồi từ các thành viên của cộng đồng về các vấn đề bảo mật mà họ có thể đã gặp phải (hoặc đã ngăn chặn) cũng như một lập luận thuyết phục về lý do tại sao phương pháp thoát ký tự hiện tại lại an toàn đủ cho mã của họ.
funseiki

12

Tôi nhận ra đây là một bài viết cũ hơn nhưng có vẻ như câu trả lời chưa bao giờ được đánh dấu nên tôi sẽ ném nó ra khỏi đó.

Liên quan đến việc kiểm tra xem một mô-đun bạn đang sử dụng có an toàn hay không, có một số lộ trình bạn có thể thực hiện. Tôi sẽ đề cập đến ưu / nhược điểm của từng loại để bạn có thể đưa ra quyết định sáng suốt hơn.

Hiện tại không có bất kỳ lỗ hổng nào cho mô-đun bạn đang sử dụng, tuy nhiên, điều này thường có thể dẫn đến cảm giác an toàn sai vì rất có thể có một lỗ hổng hiện đang khai thác gói mô-đun / phần mềm bạn đang sử dụng và bạn sẽ không được cảnh báo cho đến khi nhà cung cấp áp dụng bản sửa lỗi / bản vá.

  1. Để theo dõi các lỗ hổng bảo mật, bạn sẽ cần theo dõi danh sách gửi thư, diễn đàn, IRC và các cuộc thảo luận liên quan đến hack khác. CHUYÊN NGHIỆP: Đôi khi bạn có thể nhận ra các vấn đề tiềm ẩn trong thư viện trước khi nhà cung cấp được cảnh báo hoặc đã đưa ra bản sửa lỗi / bản vá để khắc phục nguy cơ tấn công phần mềm của họ. CON: Điều này có thể rất tốn thời gian và tài nguyên. Nếu bạn thực hiện theo lộ trình này, một bot sử dụng nguồn cấp dữ liệu RSS, phân tích cú pháp nhật ký (nhật ký trò chuyện IRC) và một trình duyệt web bằng cách sử dụng các cụm từ khóa (trong trường hợp này là node-mysql-native) và các thông báo có thể giúp giảm thời gian dùng troll các tài nguyên này.

  2. Tạo một fuzzer, sử dụng một fuzzer hoặc khung dễ bị tổn thương khác như Metasploit , sqlMap vv để giúp kiểm tra các vấn đề mà các nhà cung cấp có thể không đã tìm kiếm. CHUYÊN NGHIỆP: Điều này có thể chứng minh là một phương pháp chữa cháy chắc chắn để đảm bảo ở mức có thể chấp nhận được cho dù mô-đun / phần mềm bạn đang triển khai có an toàn cho truy cập công cộng hay không. CON: Điều này cũng trở nên mất thời gian và tốn kém. Vấn đề khác sẽ bắt nguồn từ kết quả dương tính giả cũng như việc xem xét kết quả một cách thiếu khoa học, nơi có vấn đề nhưng không được chú ý.

Thực sự bảo mật và bảo mật ứng dụng nói chung có thể rất tốn thời gian và tài nguyên. Một điều mà các nhà quản lý sẽ luôn sử dụng là một công thức để xác định hiệu quả chi phí (nhân lực, nguồn lực, thời gian, tiền lương, v.v.) khi thực hiện hai phương án trên.

Dù sao, tôi nhận ra đây không phải là câu trả lời 'có' hoặc 'không' mà bạn có thể hy vọng nhưng tôi không nghĩ rằng bất kỳ ai có thể đưa ra câu trả lời đó cho bạn cho đến khi họ thực hiện phân tích phần mềm được đề cập.


3

Tôi biết rằng câu hỏi này đã cũ nhưng đối với bất kỳ ai quan tâm, Mysql-native đã lỗi thời nên nó trở thành MySQL2 , một mô-đun mới được tạo với sự trợ giúp của nhóm của mô-đun MySQL gốc. Mô-đun này có nhiều tính năng hơn và tôi nghĩ rằng nó có những gì bạn muốn vì nó đã chuẩn bị các câu lệnh (bằng cách using.execute ()) giống như trong PHP để bảo mật hơn.

Nó cũng rất hoạt động (lần thay đổi gần đây nhất là từ ngày 2-1) Tôi đã không thử nó trước đây nhưng tôi nghĩ đó là những gì bạn muốn và hơn thế nữa.


-1

Cách dễ nhất là xử lý tất cả các tương tác cơ sở dữ liệu của bạn trong mô-đun riêng của nó mà bạn xuất ra các tuyến của mình. Nếu tuyến đường của bạn không có ngữ cảnh của cơ sở dữ liệu thì SQL không thể chạm vào nó.


Điều đó không thực sự trả lời câu hỏi của OP về cách vệ sinh.
Christopher
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.