Review commands vulnerable to SQL injection
Matches methods creating a DB command (like SqlCommand) that call an Execute method without using command parameters: prone to SQL Injection https://en.wikipedia.org/wiki/SQL_injection since malicious SQL might be injected in string parameter values.
False positives are possible; review matches and suppress issues when needed. To limit them, the rule also checks command parameters access from sub method calls (a solid indication of non-vulnerability).
Flagged Code
False positives are possible; review matches and suppress issues when needed. To limit them, the rule also checks command parameters access from sub method calls (a solid indication of non-vulnerability).
Flagged Code
public int CountUsers(SqlConnection connection, string name) {
var sql = "SELECT COUNT(*) FROM Users WHERE Name = '" + name + "'";
using var command = new SqlCommand(sql, connection); // flagged: no command parameter
return (int)command.ExecuteScalar();
}
Fixed Codepublic int CountUsers(SqlConnection connection, string name) {
const string sql = "SELECT COUNT(*) FROM Users WHERE Name = @name";
using var command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@name", name); // parameterized: not matched
return (int)command.ExecuteScalar();
}How to fix
If the method indeed injects parameter values in the SQL string, use command.Parameters.Add(...) instead. More on explicit parameters: https://stackoverflow.com/questions/4892166/how-does-sqlparameter-prevent-sql-injection
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Review commands vulnerable to SQL injection</Name>
// <Id>ND3107:ReviewCommandsVulnerableToSQLInjection</Id>
warnif count > 0
let commands = ThirdParty.Types.WithFullNameIn(
"System.Data.Common.DbCommand",
"Microsoft.Data.SqlClient.SqlCommand",
"System.Data.SqlClient.SqlCommand",
"System.Data.OleDb.OleDbCommand",
"System.Data.Odbc.OdbcCommand",
"System.Data.OracleClient.OracleCommand")
where commands.Any()
let commandCtors = commands.ChildMethods().Where(m => m.IsConstructor).ToHashSetEx()
let commandExecutes = commands.ChildMethods().Where(m => m.SimpleName.Contains("Execute")).ToHashSetEx()
let commandParameters = commands.ChildMethods().Where(m => m.IsPropertyGetter && m.SimpleNameEquals("get_Parameters")).ToHashSetEx()
from m in Application.Methods.UsingAny(commandCtors)
.UsingAny(commandExecutes)
where !m.MethodsCalled.Intersect(commandParameters).Any() &&
// Check also that non of the method call rely on command parameters to get less false positives:
!m.MethodsCalled.SelectMany(mc => mc.MethodsCalled).Intersect(commandParameters).Any()
select new { m,
createA = m.MethodsCalled.Intersect(commandCtors).First().ParentType,
calls = m.MethodsCalled.Intersect(commandExecutes).First(),
Debt = 15.ToMinutes().ToDebt(),
Severity = Severity.High
}
//<Expl>
// The *{0}* creates an instance of the *{1}* and calls the *{2}*.
// This is susceptible to *SQL Injection* as malicious SQL code
// can be injected into string parameter values.
// Instead, use *command.Parameters.Add(...)*.
//</Expl>
// <Desc>
// Matches methods creating a DB command (like *SqlCommand*) that call an
// *Execute* method without using command parameters: prone to
// **SQL Injection** https://en.wikipedia.org/wiki/SQL_injection since
// malicious SQL might be injected in string parameter values.
//
// False positives are possible; review matches and suppress issues when
// needed. To limit them, the rule also checks command parameters access
// from sub method calls (a solid indication of non-vulnerability).
//
// **Flagged Code**
// ```csharp
// public int CountUsers(SqlConnection connection, string name) {
// var sql = "SELECT COUNT(*) FROM Users WHERE Name = '" + name + "'";
// using var command = new SqlCommand(sql, connection); // flagged: no command parameter
// return (int)command.ExecuteScalar();
// }
// ```
//
// **Fixed Code**
// ```csharp
// public int CountUsers(SqlConnection connection, string name) {
// const string sql = "SELECT COUNT(*) FROM Users WHERE Name = @name";
// using var command = new SqlCommand(sql, connection);
// command.Parameters.AddWithValue("@name", name); // parameterized: not matched
// return (int)command.ExecuteScalar();
// }
// ```
// </Desc>
// <HowToFix>
// If the method indeed injects parameter values in the SQL string, use
// **command.Parameters.Add(...)** instead. More on explicit parameters:
// https://stackoverflow.com/questions/4892166/how-does-sqlparameter-prevent-sql-injection
// </HowToFix>
Open in the interactive Rules Explorer · All default rules
Security: all 39 items
- Software Composition Analysis (SCA) ND3120
- Transitive Software Composition Analysis (SCA) ND3121
- Don't hard-code secrets in constants ND3114
- Review credentials built from hard-coded values ND3115
- Don't use insecure deserializers ND3110
- Don't use weak hash algorithms (MD5, SHA1) ND3109
- Don't use DES/3DES/RC2 weak cipher algorithms ND3102
- Don't use weak password-based key derivation ND3123
- Don't use the ECB encryption mode ND3132
- Don't disable certificate validation ND3103
- Don't hard-code TLS/SSL protocol versions ND3122
- Review commands vulnerable to SQL injection ND3107
- Review data adapters vulnerable to SQL injection ND3108
- Review raw SQL built from composed strings ND3128
- Review LDAP filters composed from strings ND3137
- Don't enable external XML entity resolution (XXE) ND3111
- Review processes started with a composed arguments string ND3124
- Review web endpoints building file paths from their parameters ND3129
- Review custom archive extraction (Zip Slip) ND3135
- Review assemblies and types loaded from runtime-provided names ND3125
- Review web endpoints without [Authorize] nor [AllowAnonymous] ND3118
- Review state-changing endpoints opened to anonymous callers ND3130
- Review state-changing MVC actions without anti-forgery validation ND3119
- Review HTML-encoding bypasses ND3133
- Review explicitly disabled request validation ND3134
- Review redirects to a URL that is not validated as local ND3126
- Review request-influenced outbound HTTP calls (SSRF) ND3136
- Review insecure ASP.NET Core CORS policies and unguarded developer exception page ND3116
- Review cookies created without HttpOnly and Secure flags ND3117
- Review regular expressions without a match timeout (ReDoS) ND3112
- Review secrets compared with non-constant-time equality ND3113
- Review secrets passed to logging methods ND3127
- Review security operations that log nothing ND3131
- Don't use System.Random for security purposes ND3101
- Don't use CoSetProxyBlanket and CoInitializeSecurity ND3100
- Review publicly visible event handlers ND3104
- Pointers should not be publicly visible ND3105
- Seal methods that satisfy non-public interfaces ND3106
- Restrict sensitive APIs to reviewed components ND3138