NoSQL injection (phần 1)
I. Mở đầu
1. Giới thiệu về NoSQL
Lần đầu nghe tới NoSQL chắc hẳn phản ứng đầu tiên của mọi người là cái tên kỳ lạ này nhỉ. Vì sao có SQL rồi còn phải sinh ra NoSQL? Để trả lời câu hỏi này, chúng ta cùng xem lại một số tính chất của ngôn ngữ SQL thông thường.
Hệ quản trị cơ sở dữ liệu quan hệ (RDBMS) sử dụng ngôn ngữ SQL yêu cầu dữ liệu phải có cấu trúc chặt chẽ (như bảng, dòng, cột), phù hợp với các ứng dụng có dữ liệu mang tính cấu trúc rõ ràng. Các cơ sở dữ liệu quan hệ thường được thiết kế để mở rộng theo chiều dọc (vertical scaling), nghĩa là phải nâng cấp phần cứng máy chủ (CPU, RAM). Ngôn ngữ SQL sử dụng phép toán quan hệ thực hiện truy vấn. Từ đây dễ thấy sử dụng ngôn ngữ SQL có thể gặp một số vấn đề như sau:
- Nếu dữ liệu cần đưa vào cơ sở dữ liệu của ứng dụng có cấu trúc không chặt chẽ, rõ ràng?
- Vấn đề mở rộng - nâng cấp phần cứng bất tiện.
- Khi dữ liệu lớn kết hợp tính chất phức tạp của các phép toán truy vấn sẽ làm giảm hiệu suất.
NoSQL sinh ra để giải quyết các vấn đề về hiệu năng, mở rộng và sự phức tạp của dữ liệu phi cấu trúc mà SQL không thể xử lý tốt trong một số trường hợp hiện đại. Điều đó cũng được thể hiện qua tên gọi "Non SQL" (phi SQL) hoặc "Non relational SQL" (phi quan hệ SQL). Được giới thiệu lần đầu tiên vào năm 1998 bởi Carlo Strozzi, theo thời gian NoSQL đã thể hiện sự đột phá của mình so với SQL truyền thống, một số ưu điểm có thể kể đến như:
Lưu trữ dữ liệu phi cấu trúc hoặc bán cấu trúc
Chẳng hạn như tài liệu, key-value, cặp, hoặc đồ thị, những loại dữ liệu này không dễ dàng thể hiện trong mô hình quan hệ của SQL.
Ví dụ: các hệ thống quản lý nội dung như blog, trang web, hoặc ứng dụng tin tức. Ban đầu các bài viết hoặc trang có cấu trúc dữ liệu bao gồm tiêu đề, nội dung, tác giả, ngày đăng, sau này ứng dụng phát triển thêm cho phép bài viết có thêm hình ảnh, video.
- Với SQL, cần phải thay đổi cấu trúc bảng và thêm cột mới mỗi khi có thay đổi về cấu trúc dữ liệu, điều này mất thời gian và khó duy trì.
- Với NoSQL sử dụng MongoDB, các tài liệu JSON (hoặc BSON) có thể linh hoạt lưu trữ bài viết mà không cần thay đổi cấu trúc bảng khi thêm các trường mới như video, hình ảnh.
Mở rộng theo chiều ngang (horizontal scaling)
Có thể dễ dàng thêm nhiều máy chủ hơn vào hệ thống mà không cần nâng cấp phần cứng, rất hữu ích cho các hệ thống yêu cầu xử lý khối lượng dữ liệu lớn như mạng xã hội, e-commerce.
Ví dụ: Mạng xã hội như Instagram hoặc Facebook cần lưu trữ và xử lý hàng tỷ bài đăng, like, comment mỗi ngày từ hàng triệu người dùng.
- SQL gặp khó khăn khi phải mở rộng quy mô trên nhiều máy chủ, vì nó chủ yếu hỗ trợ mở rộng theo chiều dọc (nâng cấp phần cứng).
- NoSQL với Cassandra hỗ trợ khả năng mở rộng theo chiều ngang, có thể thêm nhiều máy chủ vào hệ thống để xử lý lưu lượng dữ liệu tăng nhanh mà không cần nâng cấp phần cứng máy chủ hiện có.
Tối ưu cho các thao tác đọc/ghi nhanh với lượng dữ liệu khổng lồ và yêu cầu truy cập thời gian thực
Thích hợp cho các ứng dụng yêu cầu hiệu suất cao, như phân tích dữ liệu lớn, trò chơi trực tuyến, ứng dụng mạng xã hội.
Ví dụ: Một trang web thương mại điện tử lớn như Amazon cần truy cập nhanh vào dữ liệu sản phẩm, giỏ hàng và trạng thái đơn hàng của hàng triệu người dùng trong thời gian thực.
- SQL cần truy vấn dữ liệu từ ổ cứng, điều này có thể làm chậm hệ thống khi số lượng truy vấn tăng đột biến trong các đợt giảm giá lớn.
- NoSQL với Redis là một cơ sở dữ liệu key-value lưu trữ dữ liệu trong bộ nhớ RAM, giúp truy cập dữ liệu rất nhanh, thích hợp cho các ứng dụng yêu cầu phản hồi nhanh như hệ thống cache.
2. hệ quản trị cơ sở dữ liệu NoSQL MongoDB
MongoDB là một trong những hệ quản trị cơ sở dữ liệu NoSQL phổ biến nhất, thuộc loại cơ sở dữ liệu document-based (dựa trên tài liệu). Thay vì lưu trữ dữ liệu dưới dạng các bảng, dòng, và cột như SQL, MongoDB lưu trữ dữ liệu dưới dạng tài liệu với cấu trúc linh hoạt, cụ thể là tài liệu JSON hoặc BSON (Binary JSON). Bài viết sẽ tập trung vào các dạng tấn công NoSQL injection nhắm vào hệ quan trị cơ sở dữ liệu MongoDB.
II. Kiến thức chuẩn bị
Trước khi đến với các kỹ thuật tấn công NoSQL, chúng ta cần nắm vững một số kiến thức cơ bản về nó.
1. Cấu trúc dữ liệu trong MongoDB
Dữ liệu trong MongoDB được lưu trữ dưới dạng tài liệu JSON hoặc BSON. Mỗi tài liệu là một tập hợp của các cặp khóa-giá trị (key-value pairs), tương tự như các hàng trong bảng của cơ sở dữ liệu SQL. Ví dụ:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"username": "admin",
"email": "admin@example.com",
"roles": ["admin", "editor"],
"last_login": "2024-10-23T18:25:43.511Z"
}
Một giá trị đặc biệt ở đây là _id
, đây là trường mặc định trong MongoDB, đóng vai trò như một khóa chính - primary key (tương tự trong cơ sở dữ liệu SQL thông thường), có giá trị là một đối tượng ObjectId
duy nhất.
Các trường khác như username
, email
, roles
được lưu trữ linh hoạt, và không bắt buộc mỗi tài liệu phải có cùng số lượng trường.
2. Truy vấn dữ liệu trong MongoDB
Truy vấn dữ liệu trong MongoDB được thực hiện bằng cách truyền một đối tượng JSON vào các phương thức như find()
, findOne()
. Ví dụ:
db.users.find({ username: "admin" });
Truy vấn này sẽ trả về tất cả các tài liệu có trường username là admin
.
MongoDB cũng hỗ trợ các toán tử đặc biệt để thực hiện các truy vấn phức tạp hơn. Một số toán tử thông dụng gồm:
$eq
: So sánh bằng.$ne
: So sánh khác.$gt
,$lt
: So sánh lớn hơn, nhỏ hơn.$in
: Kiểm tra xem giá trị có nằm trong một danh sách không.
3. NoSQL injection xảy ra như thế nào?
Trong MongoDB, do sự linh hoạt trong việc lưu trữ dữ liệu, vấn đề bảo mật và kiểm tra dữ liệu đầu vào (input) trở nên rất quan trọng. Khi dữ liệu đầu vào từ người dùng được sử dụng để thao tác trực tiếp với cơ sở dữ liệu mà không được kiểm tra và xử lý đúng cách, kẻ tấn công có thể chèn vào câu truy vấn hoặc cơ sở dữ liệu các payload độc hại dẫn đến lỗ hổng NoSQL injection.
Tài liệu tham khảo
All rights reserved