Giới thiệu về các cuộc tấn công tiêm chích NoSQL
Các cuộc tấn công tiêm nhiễm NoSQL là một hình thức tấn công mạng trong đó những người dùng độc hại khai thác các lỗ hổng trong hệ thống cơ sở dữ liệu NoSQL để có quyền truy cập trái phép hoặc thao túng dữ liệu nhạy cảm. Cũng giống như các cuộc tấn công SQL injection, NoSQL injection gây ra mối đe dọa nghiêm trọng đối với bảo mật ứng dụng. Trong bài viết này, chúng ta sẽ thảo luận về cách bảo vệ chống lại các cuộc tấn công tiêm nhiễm NoSQL trong các ứng dụng Node.js Express sử dụng MongoDB, một trong những cơ sở dữ liệu NoSQL phổ biến nhất.
Hiểu những điều cơ bản của các cuộc tấn công tiêm chích NoSQL
NoSQL so với SQL Injection
Mặc dù cả SQL và NoSQL injection đều nhắm vào lớp cơ sở dữ liệu của một ứng dụng, nhưng chúng khác nhau về cách tiếp cận. SQL injections khai thác lỗ hổng trong truy vấn SQL, thao tác dữ liệu bằng cách tiêm mã SQL độc hại. Mặt khác, việc tiêm NoSQL khai thác các lỗ hổng trong ngôn ngữ truy vấn NoSQL, thường là Ký hiệu đối tượng JavaScript (JSON).
Cách tiêm NoSQL hoạt động
Việc tiêm NoSQL tận dụng lợi thế của các ngôn ngữ được nhập yếu như JavaScript, nơi có thể xảy ra hiện tượng ép kiểu. Những kẻ tấn công thao túng dữ liệu đầu vào để thay đổi cấu trúc của truy vấn, bỏ qua các biện pháp bảo mật và giành quyền truy cập trái phép vào thông tin nhạy cảm. Ví dụ: kẻ tấn công có thể cung cấp một đối tượng thay vì một chuỗi, khiến truy vấn trả về kết quả ngoài ý muốn.
Các kỹ thuật chính để ngăn chặn các cuộc tấn công NoSQL injection
1. Sử dụng truy vấn được tham số hóa
Các truy vấn được tham số hóa giúp ngăn chặn việc tiêm NoSQL bằng cách tách cấu trúc truy vấn khỏi dữ liệu được cung cấp. Điều này ngăn chặn những kẻ tấn công sửa đổi cấu trúc của truy vấn. Chẳng hạn, khi sử dụng trình điều khiển MongoDB Node.js, hãy sử dụng toán tử $eq
để tạo truy vấn được tham số hóa:
1 2 | <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> User <span class="token punctuation">.</span> <span class="token function">findOne</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> username <span class="token operator">:</span> <span class="token punctuation">{</span> $eq <span class="token operator">:</span> req <span class="token punctuation">.</span> body <span class="token punctuation">.</span> username <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
2. Thực hiện xác thực đầu vào
Xác thực đầu vào đảm bảo rằng dữ liệu do người dùng cung cấp khớp với định dạng và loại dự kiến. Sử dụng các thư viện như Joi hoặc Validator.js để xác thực đầu vào của người dùng:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">const</span> Joi <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"joi"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> schema <span class="token operator">=</span> Joi <span class="token punctuation">.</span> <span class="token function">object</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> username <span class="token operator">:</span> Joi <span class="token punctuation">.</span> <span class="token function">string</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">alphanum</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">min</span> <span class="token punctuation">(</span> <span class="token number">3</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">max</span> <span class="token punctuation">(</span> <span class="token number">30</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">required</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> password <span class="token operator">:</span> Joi <span class="token punctuation">.</span> <span class="token function">string</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">pattern</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">RegExp</span> <span class="token punctuation">(</span> <span class="token string">"^[a-zA-Z0-9]{8,}$"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">required</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> validationResult <span class="token operator">=</span> schema <span class="token punctuation">.</span> <span class="token function">validate</span> <span class="token punctuation">(</span> req <span class="token punctuation">.</span> body <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> validationResult <span class="token punctuation">.</span> error <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">400</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> validationResult <span class="token punctuation">.</span> error <span class="token punctuation">.</span> details <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> message <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
3. Sử dụng Mặc định An toàn
Đảm bảo rằng ứng dụng của bạn sử dụng các giá trị mặc định an toàn, chẳng hạn như chế độ nghiêm ngặt trong JavaScript và các thao tác ghi an toàn trong MongoDB. Ví dụ: sử dụng các tùy chọn useNewUrlParser
, useUnifiedTopology
và useCreateIndex
khi kết nối với MongoDB:
1 2 3 4 5 6 | mongoose <span class="token punctuation">.</span> <span class="token function">connect</span> <span class="token punctuation">(</span> <span class="token string">"mongodb://localhost/mydb"</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> useNewUrlParser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> useUnifiedTopology <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> useCreateIndex <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
4. Hạn chế sử dụng các hàm JavaScript
Tránh sử dụng các hàm JavaScript, chẳng hạn như eval()
, mapReduce()
và where()
, những hàm này có thể khiến ứng dụng của bạn gặp phải các cuộc tấn công tiêm nhiễm NoSQL. Hạn chế sử dụng các chức năng này và, bất cứ khi nào có thể, hãy chọn các giải pháp thay thế an toàn hơn như đường ống tổng hợp.
5. Thường xuyên cập nhật các phụ thuộc
Luôn cập nhật các phần phụ thuộc của ứng dụng để đảm bảo bạn có các bản vá bảo mật mới nhất. Sử dụng các công cụ như npm audit
để xác định và khắc phục các lỗ hổng trong các gói của bạn.
Triển khai Ứng dụng Node.js Express an toàn
Để minh họa một ứng dụng Node.js Express an toàn được bảo vệ khỏi các cuộc tấn công tiêm nhiễm NoSQL, chúng ta sẽ tạo một lộ trình đăng nhập đơn giản:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"express"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"mongoose"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> Joi <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"joi"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> User <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"./models/user"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> express <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> mongoose <span class="token punctuation">.</span> <span class="token function">connect</span> <span class="token punctuation">(</span> <span class="token string">"mongodb://localhost/mydb"</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> useNewUrlParser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> useUnifiedTopology <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> useCreateIndex <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> schema <span class="token operator">=</span> Joi <span class="token punctuation">.</span> <span class="token function">object</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> username <span class="token operator">:</span> Joi <span class="token punctuation">.</span> <span class="token function">string</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">alphanum</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">min</span> <span class="token punctuation">(</span> <span class="token number">3</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">max</span> <span class="token punctuation">(</span> <span class="token number">30</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">required</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> password <span class="token operator">:</span> Joi <span class="token punctuation">.</span> <span class="token function">string</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">pattern</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">RegExp</span> <span class="token punctuation">(</span> <span class="token string">"^[a-zA-Z0-9]{8,}$"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">required</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token string">"/login"</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> validationResult <span class="token operator">=</span> schema <span class="token punctuation">.</span> <span class="token function">validate</span> <span class="token punctuation">(</span> req <span class="token punctuation">.</span> body <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> validationResult <span class="token punctuation">.</span> error <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">400</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> validationResult <span class="token punctuation">.</span> error <span class="token punctuation">.</span> details <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> message <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> User <span class="token punctuation">.</span> <span class="token function">findOne</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> username <span class="token operator">:</span> <span class="token punctuation">{</span> $eq <span class="token operator">:</span> req <span class="token punctuation">.</span> body <span class="token punctuation">.</span> username <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> user <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">400</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">"Invalid username or password."</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Compare passwords using bcrypt or other secure password hashing library</span> <span class="token comment">// ...</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">"Logged in successfully!"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token number">3000</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">"Server listening on port 3000"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Trong ví dụ này, chúng tôi đã tạo một ứng dụng Node.js Express đơn giản với /login
route. Chúng tôi đã sử dụng Joi để xác thực đầu vào và toán tử $eq
của MongoDB cho các truy vấn được tham số hóa. Điều này giúp bảo vệ ứng dụng chống lại các cuộc tấn công NoSQL injection.
Phần kết luận
Bảo vệ ứng dụng Node.js Express của bạn khỏi các cuộc tấn công tiêm nhiễm NoSQL là rất quan trọng để duy trì bảo mật và đảm bảo tính toàn vẹn của dữ liệu của bạn. Bằng cách áp dụng các phương pháp hay nhất chẳng hạn như sử dụng truy vấn được tham số hóa, xác thực đầu vào, mặc định bảo mật, hạn chế sử dụng hàm JavaScript và cập nhật thường xuyên các phần phụ thuộc, bạn có thể giảm nguy cơ tấn công NoSQL injection và xây dựng một ứng dụng an toàn hơn.
Và cuối cùng
Như mọi khi, tôi hy vọng bạn thích bài viết này và có một cái gì đó mới. Xin cảm ơn và hẹn gặp lại các bạn trong những bài viết tiếp theo!
Nếu các bạn thích bài viết này thì hãy cho mình 1 like và subscribe để ủng hộ mình nhé. Cảm ơn.