Nosql Injection in Aspnet
How Nosql Injection Manifests in Aspnet
NoSQL injection in ASP.NET applications typically occurs when user input is directly concatenated into database queries without proper parameterization, especially when using NoSQL databases like MongoDB via the official C# driver. Unlike SQL injection, NoSQL injection exploits the document-based query structure, allowing attackers to manipulate query logic, bypass authentication, or exfiltrate data.
In ASP.NET Core, a common vulnerable pattern involves using the MongoDB driver’s Builders<T>.Filter methods with unsanitized input. For example, consider an API endpoint that authenticates users by querying a MongoDB collection:
[HttpPost("login")]
public async Task Login([FromBody] LoginModel model)
{
var filter = Builders<User>.Filter.Eq(u => u.Username, model.Username) &
Builders<User>.Filter.Eq(u => u.Password, model.Password);
var user = await _context.Users.Find(filter).FirstOrDefaultAsync();
if (user != null)
return Ok(new { Token = GenerateJwtToken(user) });
return Unauthorized();
}
public class LoginModel
{
public string Username { get; set; }
public string Password { get; set; }
}
If an attacker supplies a username like "admin" and a password like { "\$ne": "" }, the resulting filter becomes:
Builders<User>.Filter.Eq(u => u.Username, "admin") &
Builders<User>.Filter.Eq(u => u.Password, new BsonDocument([["\$ne", ""]]))
This exploits MongoDB’s \$ne (not equal) operator, causing the password check to match any document where the password field is not empty—effectively bypassing authentication. Similar attacks can use \$regex for blind data exfiltration or \$where for JavaScript execution (if enabled).
Another vector appears in ASP.NET Web API controllers using raw JSON deserialization into BsonDocument or dynamic objects, where user-controlled input can inject query operators directly into the filter.
Aspnet-Specific Detection
Detecting NoSQL injection in ASP.NET requires analyzing both code patterns and runtime behavior. Static analysis can identify risky usages of the MongoDB driver where user input flows into filter builders without validation or parameterization. However, black-box scanners like middleBrick detect this vulnerability by probing unauthenticated endpoints with payloads designed to trigger NoSQL-specific responses.
middleBrick’s active testing includes injecting NoSQL operators (e.g., \$ne, \$regex, \$gt) into common input fields (headers, query strings, JSON bodies) and analyzing responses for anomalies. For instance, if a login endpoint returns a successful authentication token when provided with a password payload like {"\$ne": ""}, it indicates a potential NoSQL injection flaw. The scanner correlates response changes (status codes, response times, data leakage) with injected payloads to confirm exploitability.
middleBrick also checks for error messages that reveal NoSQL syntax (e.g., MongoDB exception details in HTTP 500 responses), though many applications suppress these. More reliably, it uses behavioral detection: comparing baseline responses to those containing injection attempts. If a payload like {"\$regex": "^adm.*"} in a username field causes a different response timing or data exposure (e.g., returning user data for partial matches), it suggests a \$regex injection vector.
The tool’s OpenAPI/Swagger analysis further improves detection by identifying endpoints that accept user input likely to be used in NoSQL queries (e.g., parameters named "filter", "query", "username") and prioritizing them for active testing. This combination of spec-aware probing and behavioral analysis allows middleBrick to detect NoSQL injection in ASP.NET applications without source code access or credentials.
Aspnet-Specific Remediation
Fixing NoSQL injection in ASP.NET applications centers on preventing user input from being interpreted as query operators. The primary defense is to avoid constructing filters from raw user input. Instead, use explicit field comparisons and validate or sanitize input before use.
For the login example, remediate by ensuring username and password are treated strictly as strings, not as executable query components. One approach is to explicitly convert input to strings and reject any input containing NoSQL operator syntax:
[HttpPost("login")]
public async Task Login([FromBody] LoginModel model)
{
// Validate input: reject strings containing NoSQL operators
if (model.Username.Contains("$") || model.Password.Contains("$"))
return BadRequest("Invalid input");
var filter = Builders<User>.Filter.Eq(u => u.Username, model.Username) &
Builders<User>.Filter.Eq(u => u.Password, model.Password);
var user = await _context.Users.Find(filter).FirstOrDefaultAsync();
if (user != null)
return Ok(new { Token = GenerateJwtToken(user) });
return Unauthorized();
}
However, blacklisting is error-prone. A stronger approach is to use a strict allowlist for expected input patterns (e.g., alphanumeric only for usernames) or to use the MongoDB driver’s parameterized query equivalents. While the C# driver doesn’t have direct parameterization like ADO.NET, you can safely build filters by ensuring user data is only used as literal values:
// Safe: user input is treated as literal BsonValue
var usernameFilter = Builders<User>.Filter.Eq(u => u.Username, model.Username);
var passwordFilter = Builders<User>.Filter.Eq(u => u.Password, model.Password);
var filter = usernameFilter & passwordFilter;
This is safe because the driver serializes model.Username and model.Password as literal BsonString values, not as executable document structures—even if the input contains \$ne, it’s stored as a string, not interpreted as an operator.
For more complex queries, avoid deserializing user input directly into BsonDocument. Instead, map input to strongly typed C# models:
// Unsafe: allows injection via JSON
[HttpPost("search")]
public async Task Search([FromBody] BsonDocument filter)
{
var results = await _context.Items.Find(filter).ToListAsync();
return Ok(results);
}
// Safe: use a defined model
public class SearchFilter
{
public string Category { get; set; }
public decimal? MinPrice { get; set; }
public decimal? MaxPrice { get; set; }
}
[HttpPost("search")]
public async Task Search([FromBody] SearchFilter filter)
{
var builder = Builders<Item>.Filter.Empty;
if (!string.IsNullOrEmpty(filter.Category))
builder &= Builders<Item>.Filter.Eq(i => i.Category, filter.Category);
if (filter.MinPrice.HasValue)
builder &= Builders<Item>.Filter.Gte(i => i.Price, filter.MinPrice.Value);
if (filter.MaxPrice.HasValue)
builder &= Builders<Item>.Filter.Lte(i => i.Price, filter.MaxPrice.Value);
var results = await _context.Items.Find(builder).ToListAsync();
return Ok(results);
}
Additionally, apply input validation using ASP.NET Core’s built-in attributes or middleware. For example, use [RegularExpression] to restrict input to safe characters:
public class LoginModel
{
[RegularExpression("^[a-zA-Z0-9_]{3,20}$")]
public string Username { get; set; }
[RegularExpression("^[\\S]{8,50}$")]
public string Password { get; set; }
}
Finally, configure the MongoDB driver to disable JavaScript execution (\$where, \$func) if not needed, via MongoClientSettings:
var settings = MongoClient.FromUrl(url);
settings.ServerApi = new ServerApi(ServerApiVersion.V1);
settings.SslSettings = new SslSettings() { EnabledSslProtocols = System.Net.Security.SslProtocols.Tls12 };
// Disable scripting if not required
var client = new MongoClient(settings);
These practices ensure user input remains data, not executable query logic, effectively mitigating NoSQL injection in ASP.NET applications.
Frequently Asked Questions
Can NoSQL injection in ASP.NET lead to remote code execution?
\$where or \$func with unsanitized input, an attacker could inject arbitrary JavaScript. For example, a payload like {"\$where": "function() { return true; print('exploited'); }"} might execute code server-side. However, modern MongoDB versions disable scripting by default, and ASP.NET applications rarely use these operators. The primary risk remains authentication bypass and data exfiltration.Does using ASP.NET Core’s built-in JSON deserialization prevent NoSQL injection?
System.Text.Json or Newtonsoft.Json) safely maps JSON to C# objects, but if those objects are then used to construct NoSQL queries without care (e.g., spreading user input into a BsonDocument), injection can still occur. Safety depends on how the deserialized data is used in the database query layer—not the deserialization itself.