Injection Flaws on Azure
How Injection Flaws Manifests in Azure
Injection flaws in Azure environments typically occur when untrusted data is sent to an interpreter as part of a command or query. Azure's diverse service ecosystem creates unique injection vectors that developers must understand to secure their applications effectively.
SQL Injection in Azure SQL Databases remains one of the most critical injection flaws. When constructing dynamic SQL queries with user input, attackers can manipulate the query logic. For example, in an Azure Function using SQL Server:
using System.Data.SqlClient;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string userId = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "id", true) == 0)
.Value;
using (SqlConnection conn = new SqlConnection(
"Server=tcp:yourserver.database.windows.net;Database=yourdb;User ID=...;Password=..."))
{
conn.Open();
string query = "SELECT * FROM Users WHERE UserId = '" + userId + "'";
SqlCommand cmd = new SqlCommand(query, conn);
SqlDataReader reader = cmd.ExecuteReader();
// Vulnerable: userId = "1 OR 1=1 --" returns all users
}
}Command Injection in Azure App Services occurs when user input is passed to operating system commands. Azure's Linux-based App Services and Windows App Services are both vulnerable:
using System.Diagnostics;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string fileName = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "file", true) == 0)
.Value;
Process process = new Process();
process.StartInfo.FileName = "/bin/ls";
process.StartInfo.Arguments = fileName; // Vulnerable to injection
process.Start();
// fileName = "-la; rm -rf /" could be catastrophic
}Azure Storage Table injection targets the Table service query syntax. When constructing Table queries with user input, attackers can manipulate OData filters:
using Microsoft.WindowsAzure.Storage.Table;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string username = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "user", true) == 0)
.Value;
CloudTable table = GetTableReference();
TableQuery<DynamicTableEntity> query =
new TableQuery<DynamicTableEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey",
QueryComparisons.Equal, username));
// If username contains special OData characters, query can be manipulated
}Azure Functions and Logic Apps are particularly vulnerable to injection when processing HTTP triggers or integrating with external systems. The serverless nature means injection flaws can have broader blast radius since functions often have elevated permissions.
Azure-Specific Detection
Detecting injection flaws in Azure requires both static analysis and dynamic testing approaches. Azure Security Center provides baseline protection by scanning for common injection patterns, but comprehensive detection requires specialized tools.
middleBrick's Azure-specific scanning identifies injection vulnerabilities across your Azure API endpoints. The scanner tests for SQL injection by sending specially crafted payloads to detect whether user input is being concatenated into queries. For Azure SQL Database endpoints, it attempts common injection patterns like:
-- Universal SQL injection test
' OR '1'='1
' OR 1=1 --
' OR 'a'='a
' OR 1=1 /*For Azure Storage Table endpoints, middleBrick tests OData injection by attempting to manipulate query operators and filter conditions. The scanner sends payloads that attempt to bypass authentication or retrieve unauthorized data.
Command injection detection in Azure App Services involves sending payloads designed to execute system commands. The scanner tests for patterns like:
|| ls -la
& echo vulnerable
; cat /etc/passwd
`id`Azure API Management provides centralized logging that can help detect injection attempts. By enabling diagnostic logging and monitoring for suspicious patterns in request parameters, you can identify potential injection attacks in production.
For Azure Functions, Application Insights can be configured to detect injection patterns by setting up custom alerts on specific error patterns or unusual database query patterns. The Azure Monitor logs can be queried for SQL error messages that might indicate injection attempts.
middleBrick's LLM/AI Security module is particularly relevant for Azure OpenAI deployments, where prompt injection can occur. The scanner tests for system prompt extraction and instruction override attempts that could compromise your AI models.
Azure DevOps pipelines can be configured with middleBrick's GitHub Action to automatically scan your APIs before deployment, catching injection flaws in the development lifecycle rather than in production.
Azure-Specific Remediation
Remediating injection flaws in Azure requires adopting parameterized queries and proper input validation. For Azure SQL Database, always use parameterized queries instead of string concatenation:
using System.Data.SqlClient;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string userId = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "id", true) == 0)
.Value;
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
string query = "SELECT * FROM Users WHERE UserId = @UserId";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@UserId", userId);
// Safe: parameter prevents injection
SqlDataReader reader = cmd.ExecuteReader();
}
}For Azure Storage Table operations, use the TableQuery class with proper parameterization:
using Microsoft.WindowsAzure.Storage.Table;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string username = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "user", true) == 0)
.Value;
CloudTable table = GetTableReference();
TableQuery<DynamicTableEntity> query =
new TableQuery<DynamicTableEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey",
QueryComparisons.Equal, username));
// Safe: GenerateFilterCondition handles escaping
TableContinuationToken token = null;
do
{
var queryResult = await table.ExecuteQuerySegmentedAsync(query, token);
token = queryResult.ContinuationToken;
} while (token != null);
}For Azure App Services, avoid using Process.Start with user input. If system commands are necessary, implement strict validation:
using System.Diagnostics;
using System.Text.RegularExpressions;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
string fileName = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "file", true) == 0)
.Value;
// Strict validation: only alphanumeric, hyphen, underscore, dot
if (!Regex.IsMatch(fileName, @"^[a-zA-Z0-9._-]+$"))
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Invalid filename");
}
Process process = new Process();
process.StartInfo.FileName = "/bin/ls";
process.StartInfo.Arguments = fileName;
process.Start();
}Azure API Management policies can add an additional layer of protection by validating input parameters before they reach your backend services. Create inbound policies that validate and sanitize input:
<policies>
<inbound>
<base/>
<validate-parameters header-name="username"
regex="^[a-zA-Z0-9_]{3,20}$"
error-message="Invalid username format" />
</inbound>
</policies>For Azure Functions, enable Application Insights and configure custom telemetry to track database query patterns. Unusual query patterns can indicate injection attempts. Also, implement Azure AD authentication to ensure only authorized users can access your functions.
Azure Key Vault should be used for all database credentials and connection strings, preventing hardcoded secrets that could be exposed through injection flaws. The managed identity feature eliminates the need to store credentials entirely for many Azure services.