Overview
SQL injection remains one of the most critical security risks for data-driven applications. This guide covers advanced techniques and best practices to prevent injection attacks beyond basic parameterization.
Parameterized Queries
Always use prepared statements with bound parameters. This ensures that user input is treated as data, not executable code.
using (var cmd = new SqlCommand("SELECT * FROM Users WHERE Email = @email", conn)) {
cmd.Parameters.Add("@email", SqlDbType.NVarChar, 255).Value = userEmail;
using (var reader = cmd.ExecuteReader()) {
// process results
}
}
Stored Procedures
Encapsulate business logic inside the database and expose only necessary parameters.
CREATE PROCEDURE dbo.GetUserByEmail
@Email NVARCHAR(255)
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM dbo.Users WHERE Email = @Email;
END;
ORMs & Query Builders
Modern ORMs automatically parameterize queries. Ensure you avoid raw string concatenation.
var user = context.Users
.Where(u => u.Email == userEmail)
.FirstOrDefault();
Input Validation & Sanitization
Validate input against a whitelist of allowed characters or patterns before processing.
function isValidEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
Least‑Privilege Principle
Configure database accounts with only the permissions required for their tasks. Avoid using admin accounts for application access.
Safe Dynamic SQL
If dynamic SQL is unavoidable, use sp_executesql with parameters.
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'SELECT * FROM dbo.Orders WHERE OrderDate > @date';
EXEC sp_executesql @sql, N'@date DATE', @date = @StartDate;
Testing & Tools
- Static code analysis (e.g., SonarQube)
- Dynamic scanning (e.g., OWASP ZAP)
- Fuzz testing with sqlmap