Một kĩ thuật đơn giản nhưng hiệu quả trong việc kiểm thử các ứng dụng web. Đặc biệt là các ứng dụng viết trên nền NodeJS và MongoDB. Kỹ thuật Mongodb Injection khá giống SQL Injection (SQLi). Tuy nhiên đơn giản hơn nhiều do không cần hoàn thành những chuỗi kí tự phức tạp hay lạ thường. Những ví dụ trong bài viết sử dụng ExpressJS. Đây là framework lập trình ứng dụng web phổ biến dành cho NodeJs.
Sơ lược về SQL Injection
Câu truy vấn SQL trả về TRUE. Ví dụ về câu truy vấn SQL dưới đây được sử dụng trong xác thực người dùng khi tên tài khoản và mật khẩu được gửi lên ứng dụng:SELECT * FROM users WHERE username = '$username' AND password = '$password'Nếu câu lệnh này không được chuẩn bị hay xử lý đúng khi tạo ra, tin tặc có thể đưa thêm' or 1=1--vào trường username nhằm tạo tạo một bypass login đơn giản nhất như sau:SELECT * FROM users WHERE username = '' or 1=1--' AND password = ''Hiện nay, kiểu tấn công cổ điển và biến thể của nó vẫn đang được sử dụng để xác định lỗ hổng trong xử lý câu lệnh SQL.
Sơ lược về MongoDB Injection
Dù SQL Injection vẫn là một kiểu tấn công ứng dụng web phổ biến, nhưng nó không còn phát tán rộng rãi như trước kia nữa. Rất nhiều ứng dụng web hiện nay lựa chọn các cơ chế lưu trữ đơn giản hơn như cung cấp cơ sở dữ liệu NoSQL như MongoDB. Cơ sở dữ liệu NoSQL không chỉ được phát triển theo hướng đơn giản hóa mà còn cải thiện bảo mật thông qua việc loại bỏ hoàn toàn ngôn ngữ SQL và phụ thuộc vào cơ chế truy vấn có cấu trúc đơn giản hơn như JSON và JavaScript. Câu lệnh SQL ở ví dụ truy vấn sẽ được viết như sau trong MongoDB:db.users.find({username: username, password: password});Chúng ta không còn phải xử lý với một ngôn ngữ truy vấn dưới dạng chuỗi kí tự. Do đó có thể cho rằng việc tiêm nhiễm chuỗi độc hại vào là không thể. Tuy nhiên, sét về tính bảo mật, vẫn còn rất nhiều yếu tốt khác có thể ảnh hưởng. Ví dụ, giả sử tại trường username, hoặc tham số được truyền vào dưới dạng một đối tượng JSON. Nếu đầu vào là một JSON Document, tin tặc có thể bypass login tương tự như SQL Injection:{
"username": {"$gt": ""},
"password": {"$gt": ""}
}Code xử lý yêu cầu có dạng như sau:app.post('/', function (req, res) {
db.users.find({username: req.body.username, password: req.body.password}, function (err, users) {
// TODO: handle the rest
});
});Ở đoạn code ExpressJS xử lý trên, trường username và password không được kiểm duyệt để đảm bảo chúng là chuỗi kí tự. Khi một JSON Document được phân tích, những trường này có thể chứa bất kì chuỗi kí tự nào. Và những chuỗi kí tự đó có thể được dùng để tạo ra một cấu trúc truy vấn khác. Trong MongoDB, trường $gt có nghĩa đặc biệt, được sử dụng trong so sánh lớn hơn. Do đó username và password từ cơ sở dữ liệu sẽ được so sánh với dữ liệu nhập vào là chuỗi kí tự trống “” và kết quả câu lệnh trả về là TRUE. Request dùng để khai thác sẽ có dạng như sau:POST http://target/ HTTP/1.1
Content-Type: application/json
{
"username": {"$gt": ""},
"password": {"$gt": ""}
}Sử dụng khai thác kết hợp NodeJS và MongoDB Ví dụ sử dụng cơ chế truyền tải dữ liệu JSON để giải thích kiểu tấn công dễ hiểu hơn. Tuy nhiên, JSON vẫn chưa phổ biến như url-encoded key-value hay còn gọi là urlencoding. Sử dụng phần thân và tham số truy vấn trong định dạng urlencoding liệu có an toàn? Trong ExpressJS ta vẫn có thể bypass ví dụ trên thông qua một chuỗi truy vấn đơn giản như sau:POST http://target/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username[$gt]=&password[$gt]=Chuỗiusername[$gt]=là một cú pháp đặc biệt sử dụng trong module qs (sử dụng mặc định trong ExpressJS và phần mềm trung gian body-parser). Cú pháp tương đương với việc tạo ra một JavaScript object/hash với tham số $gt và không có giá trị. Thực chất, request trên sẽ trả về kết quả là một đối tượng JavaScript như sau:
{
"username": {"$gt": undefined},
"password": {"$gt": undefined}
}
Nếu so sánh với đối tượng trong ví dụ trước, ta sẽ thấy chúng hoàn toàn giống nhau.
Ví dụ
Hai project sau được dùng để minh họa lỗ hổng trong thực tế. Project đầu tiên sử dụng kiểu giá trị urlencoded và project thứ hai sử dụng JSON. Bạn đọc có thể đọc thêm tệp tin README để có thêm thông tin về lỗ hổng MongoDB Injection.