SQL injection xảy ra khi dữ liệu không đáng tin được ghép vào cấu trúc SQL, khiến input của người dùng biến thành một phần câu lệnh.
1 | # Nguy hiểm |
Kẻ tấn công không cần đội hoodie trong phòng tối. Một dấu nháy đúng chỗ thường đã đủ làm ngày của bạn dài hơn.
Dùng parameter binding
1 | User.where("email = ?", params[:email]) |
ActiveRecord tách cấu trúc query khỏi value và bind parameter phù hợp.
Những API vẫn cần cảnh giác
Không phải method ActiveRecord nào cũng tự sanitize mọi string:
1 | User.order(params[:sort]) |
Tên cột, hướng sort và SQL fragment là identifier/cấu trúc, không phải value bind thông thường. Hãy dùng allowlist:
1 | SORT_COLUMNS = { |
Raw SQL
Nếu thật sự cần SQL thủ công, vẫn bind parameter:
1 | sql = User.sanitize_sql_array([ |
Tốt hơn nữa, dùng adapter/query API hỗ trợ bind thay vì tự escape. Không tự viết hàm thay ' thành ''; bảo mật không nên phụ thuộc vào một bài replace rất tự tin.
Defense in depth
- Database user chỉ có quyền cần thiết.
- Không trả database error chi tiết ra client.
- Log và monitor query bất thường nhưng không log sensitive input.
- Validate input để bảo vệ domain; parameterize để bảo vệ SQL. Hai việc khác nhau.
- Test các query dynamic, đặc biệt sort/filter/reporting.
Prepared statement không sửa được logic authorization. Query an toàn vẫn có thể trả dữ liệu của người khác nếu policy sai.