"Chúng ta dùng ORM nên không bị SQL injection"
Câu đó gần đúng, và phần "gần" là phần đáng học.
EF Core tham số hoá mọi truy vấn LINQ. Không có cách nào viết _db.Users.Where(u => u.Email == email) mà bị injection — giá trị luôn thành tham số. Nếu 100% truy vấn của bạn là LINQ thì câu nói trên là đúng.
Vấn đề là 100% không bao giờ xảy ra, vì ba lý do đều hợp lý:
- Có truy vấn LINQ không diễn tả được — window function, CTE đệ quy,
INSERT ... ON CONFLICT, full-text search. - Có truy vấn LINQ diễn tả được nhưng dịch ra SQL tệ — và ai đó đo được, rồi viết lại bằng SQL thô.
- Có người copy một câu SQL từ pgAdmin vào code vì nó đã chạy đúng ở đó.
Nên câu hỏi đúng không phải "chúng ta có dùng ORM không" mà "những cửa sau của ORM đang được dùng ở đâu, và ai đọc lại chúng".
Danh sách cửa sau của EF Core — đây là danh sách đáng dán lên tường:
| API | Có tham số hoá tự động? |
|---|---|
FromSqlInterpolated, ExecuteSqlInterpolated | Có — giá trị nội suy thành tham số |
FromSql (EF 7+, nhận FormattableString) | Có — cùng cơ chế |
FromSqlRaw, ExecuteSqlRaw | Không — chuỗi vào nguyên văn |
Database.GetDbConnection() + CommandText | Không — ADO.NET thô |
EF.Functions.Like với pattern ghép chuỗi | Có tham số, nhưng pattern có thể là injection logic |
Dapper Query<T>("... " + x) | Không — Dapper không phải ORM sinh SQL |
Cái bẫy tinh vi nhất nằm ở hai dòng đầu và dòng thứ ba: FromSqlInterpolated($"...{x}") an toàn, còn FromSqlRaw($"...{x}") không — và hai dòng đó khác nhau đúng ba ký tự. Đây là chỗ một cái test đáng giá hơn một quy ước.
Bình luận
Bình luận cần tài khoản đã hoàn thành ít nhất một bài học. Điều kiện đó là thứ giữ cho luồng thảo luận này còn đáng đọc: mỗi ý kiến gắn với một người có thể bị hỏi lại, và reputation tích luỹ theo thời gian.
Bạn vẫn đọc được toàn bộ bình luận dưới đây mà không cần tài khoản. Đăng nhập xong bạn sẽ quay lại đúng chỗ này, không phải đầu trang.
Đang tải bình luận…