746 lines
27 KiB
C#
Executable File
746 lines
27 KiB
C#
Executable File
using MarketAlly.AIPlugin;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MarketAlly.AIPlugin.Security.Plugins
|
|
{
|
|
/// <summary>
|
|
/// Analyzes input validation patterns and suggests security improvements
|
|
/// </summary>
|
|
[AIPlugin("InputValidation", "Analyzes input validation patterns and suggests security improvements")]
|
|
public class InputValidationPlugin : IAIPlugin
|
|
{
|
|
[AIParameter("Full path to the file to analyze", required: true)]
|
|
public string FilePath { get; set; }
|
|
|
|
[AIParameter("Check for SQL injection protection", required: false)]
|
|
public bool CheckSqlInjection { get; set; } = true;
|
|
|
|
[AIParameter("Check for XSS protection", required: false)]
|
|
public bool CheckXssProtection { get; set; } = true;
|
|
|
|
[AIParameter("Check for CSRF protection", required: false)]
|
|
public bool CheckCsrfProtection { get; set; } = true;
|
|
|
|
[AIParameter("Analyze sanitization patterns", required: false)]
|
|
public bool AnalyzeSanitization { get; set; } = true;
|
|
|
|
[AIParameter("Generate validation suggestions", required: false)]
|
|
public bool GenerateSuggestions { get; set; } = true;
|
|
|
|
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
|
|
{
|
|
["filePath"] = typeof(string),
|
|
["checkSqlInjection"] = typeof(bool),
|
|
["checkXssProtection"] = typeof(bool),
|
|
["checkCsrfProtection"] = typeof(bool),
|
|
["analyzeSanitization"] = typeof(bool),
|
|
["generateSuggestions"] = typeof(bool)
|
|
};
|
|
|
|
// Input validation patterns
|
|
private static readonly Dictionary<string, (Regex Pattern, string Type, string Severity, string Description)> ValidationPatterns = new()
|
|
{
|
|
// SQL Injection Vulnerabilities
|
|
["sql_raw_query"] = (new Regex(@"(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)\s+.*\+.*['""]", RegexOptions.IgnoreCase),
|
|
"SQLInjection", "High", "Raw SQL query with string concatenation"),
|
|
["sql_format_string"] = (new Regex(@"String\.Format\s*\(\s*['""].*?(SELECT|INSERT|UPDATE|DELETE)", RegexOptions.IgnoreCase),
|
|
"SQLInjection", "High", "SQL query using String.Format"),
|
|
["sql_interpolation"] = (new Regex(@"\$['""].*?(SELECT|INSERT|UPDATE|DELETE).*?\{.*?\}", RegexOptions.IgnoreCase),
|
|
"SQLInjection", "Medium", "SQL query using string interpolation"),
|
|
["entity_raw_sql"] = (new Regex(@"(FromSqlRaw|ExecuteSqlRaw|Database\.ExecuteSqlCommand)\s*\(.*\+", RegexOptions.IgnoreCase),
|
|
"SQLInjection", "High", "Entity Framework raw SQL with concatenation"),
|
|
|
|
// XSS Vulnerabilities
|
|
["innerHTML_assignment"] = (new Regex(@"\.innerHTML\s*=.*['""].*\+", RegexOptions.IgnoreCase),
|
|
"XSS", "High", "Direct innerHTML assignment with concatenation"),
|
|
["document_write"] = (new Regex(@"document\.write\s*\(.*\+", RegexOptions.IgnoreCase),
|
|
"XSS", "High", "Document.write with user input"),
|
|
["eval_usage"] = (new Regex(@"eval\s*\(.*['""].*\+", RegexOptions.IgnoreCase),
|
|
"XSS", "Critical", "eval() function with user input"),
|
|
["html_raw"] = (new Regex(@"Html\.Raw\s*\(.*[^\)]", RegexOptions.IgnoreCase),
|
|
"XSS", "Medium", "Html.Raw without proper encoding"),
|
|
["response_write"] = (new Regex(@"Response\.Write\s*\(.*[^\)]", RegexOptions.IgnoreCase),
|
|
"XSS", "Medium", "Response.Write without encoding"),
|
|
|
|
// Missing Input Validation
|
|
["missing_validation"] = (new Regex(@"(Request\.|HttpContext\.Request\.|req\.|params\.|query\.).*(?!\s*(IsValid|Validate|Check|Sanitize))", RegexOptions.IgnoreCase),
|
|
"Validation", "Medium", "Request parameter without validation"),
|
|
["direct_model_binding"] = (new Regex(@"public\s+\w+\s+\w+\s*\([^)]*\bModel\b[^)]*\)(?!.*\[ValidateAntiForgeryToken\])", RegexOptions.IgnoreCase),
|
|
"Validation", "Medium", "Model binding without validation attributes"),
|
|
|
|
// CSRF Protection
|
|
["missing_antiforgery"] = (new Regex(@"(HttpPost|POST).*public.*(?!\[ValidateAntiForgeryToken\])", RegexOptions.IgnoreCase | RegexOptions.Singleline),
|
|
"CSRF", "High", "POST action without anti-forgery token"),
|
|
["form_without_token"] = (new Regex(@"<form[^>]*method\s*=\s*['""]post['""][^>]*>(?!.*@Html\.AntiForgeryToken)", RegexOptions.IgnoreCase),
|
|
"CSRF", "High", "POST form without anti-forgery token"),
|
|
|
|
// Path Traversal
|
|
["path_traversal"] = (new Regex(@"(File\.|Path\.|Directory\.).*\+.*['""]", RegexOptions.IgnoreCase),
|
|
"PathTraversal", "High", "File path concatenation vulnerability"),
|
|
["unsafe_file_access"] = (new Regex(@"(File\.ReadAllText|File\.WriteAllText|File\.Open)\s*\([^)]*Request\.", RegexOptions.IgnoreCase),
|
|
"PathTraversal", "High", "Direct file access with user input"),
|
|
|
|
// Command Injection
|
|
["process_start"] = (new Regex(@"Process\.Start\s*\([^)]*\+", RegexOptions.IgnoreCase),
|
|
"CommandInjection", "Critical", "Process execution with concatenated input"),
|
|
["cmd_execution"] = (new Regex(@"(cmd\.exe|powershell|bash|sh)\s*.*\+", RegexOptions.IgnoreCase),
|
|
"CommandInjection", "Critical", "Command execution with user input"),
|
|
|
|
// Weak Validation Patterns
|
|
["regex_injection"] = (new Regex(@"new\s+Regex\s*\([^)]*\+", RegexOptions.IgnoreCase),
|
|
"RegexInjection", "Medium", "Dynamic regex creation with user input"),
|
|
["weak_email_validation"] = (new Regex(@"@.*\.\w+", RegexOptions.IgnoreCase),
|
|
"WeakValidation", "Low", "Weak email validation pattern"),
|
|
["missing_length_check"] = (new Regex(@"(string|String)\s+\w+.*(?!.*\.Length)", RegexOptions.IgnoreCase),
|
|
"WeakValidation", "Low", "String parameter without length validation"),
|
|
|
|
// Deserialization Issues
|
|
["unsafe_deserialization"] = (new Regex(@"(JsonConvert\.DeserializeObject|XmlSerializer|BinaryFormatter).*Request\.", RegexOptions.IgnoreCase),
|
|
"Deserialization", "High", "Unsafe deserialization of user input"),
|
|
["xml_external_entities"] = (new Regex(@"XmlDocument.*(?!.*XmlResolver\s*=\s*null)", RegexOptions.IgnoreCase),
|
|
"XXE", "High", "XML parsing without disabling external entities")
|
|
};
|
|
|
|
// Positive validation patterns (good practices)
|
|
private static readonly Dictionary<string, Regex> GoodPatterns = new()
|
|
{
|
|
["parameterized_query"] = new Regex(@"(SqlParameter|DbParameter|@\w+)", RegexOptions.IgnoreCase),
|
|
["entity_framework_linq"] = new Regex(@"(\.Where\(|\.Select\(|\.Any\(|\.FirstOrDefault\()", RegexOptions.IgnoreCase),
|
|
["html_encode"] = new Regex(@"(Html\.Encode|HttpUtility\.HtmlEncode|AntiXssEncoder)", RegexOptions.IgnoreCase),
|
|
["antiforgery_token"] = new Regex(@"(\[ValidateAntiForgeryToken\]|@Html\.AntiForgeryToken)", RegexOptions.IgnoreCase),
|
|
["data_annotations"] = new Regex(@"\[(Required|StringLength|Range|RegularExpression|EmailAddress)", RegexOptions.IgnoreCase),
|
|
["input_sanitization"] = new Regex(@"(Sanitize|Clean|Validate|Trim|Escape)", RegexOptions.IgnoreCase),
|
|
["path_validation"] = new Regex(@"(Path\.GetFullPath|Path\.IsPathRooted|ValidatePath)", RegexOptions.IgnoreCase),
|
|
["safe_deserialization"] = new Regex(@"(TypeNameHandling\.None|JsonSerializerSettings.*TypeNameHandling)", RegexOptions.IgnoreCase)
|
|
};
|
|
|
|
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
|
|
{
|
|
try
|
|
{
|
|
// Extract parameters
|
|
string filePath = parameters["filePath"].ToString();
|
|
bool checkSqlInjection = parameters.TryGetValue("checkSqlInjection", out var sqlObj) ? Convert.ToBoolean(sqlObj) : true;
|
|
bool checkXssProtection = parameters.TryGetValue("checkXssProtection", out var xssObj) ? Convert.ToBoolean(xssObj) : true;
|
|
bool checkCsrfProtection = parameters.TryGetValue("checkCsrfProtection", out var csrfObj) ? Convert.ToBoolean(csrfObj) : true;
|
|
bool analyzeSanitization = parameters.TryGetValue("analyzeSanitization", out var sanitObj) ? Convert.ToBoolean(sanitObj) : true;
|
|
bool generateSuggestions = parameters.TryGetValue("generateSuggestions", out var suggestObj) ? Convert.ToBoolean(suggestObj) : true;
|
|
|
|
// Validate path exists
|
|
if (!File.Exists(filePath) && !Directory.Exists(filePath))
|
|
{
|
|
return new AIPluginResult(
|
|
new FileNotFoundException($"Path not found: {filePath}"),
|
|
"Path not found"
|
|
);
|
|
}
|
|
|
|
// Collect files to analyze
|
|
var filesToAnalyze = GetFilesToAnalyze(filePath);
|
|
var results = new InputValidationResults
|
|
{
|
|
FilePath = filePath,
|
|
FileName = Path.GetFileName(filePath) ?? "Multiple Files",
|
|
FileType = Directory.Exists(filePath) ? "Directory" : GetFileType(Path.GetExtension(filePath).ToLower())
|
|
};
|
|
|
|
// Perform analysis on all files
|
|
foreach (var file in filesToAnalyze)
|
|
{
|
|
var content = await File.ReadAllTextAsync(file);
|
|
|
|
if (checkSqlInjection)
|
|
{
|
|
await AnalyzeSqlInjectionProtection(content, results);
|
|
}
|
|
|
|
if (checkXssProtection)
|
|
{
|
|
await AnalyzeXssProtection(content, results);
|
|
}
|
|
|
|
if (checkCsrfProtection)
|
|
{
|
|
await AnalyzeCsrfProtection(content, results);
|
|
}
|
|
|
|
if (analyzeSanitization)
|
|
{
|
|
await AnalyzeSanitizationMethod(content, results);
|
|
}
|
|
|
|
// Analyze general validation patterns
|
|
await AnalyzeGeneralValidation(content, results);
|
|
}
|
|
|
|
// Calculate security score
|
|
results.SecurityScore = CalculateSecurityScore(results);
|
|
|
|
// Generate suggestions if requested
|
|
if (generateSuggestions)
|
|
{
|
|
results.Suggestions = GenerateSecuritySuggestions(results);
|
|
}
|
|
|
|
return new AIPluginResult(results,
|
|
$"Input validation analysis completed. Found {results.GetTotalIssues()} security issues with score {results.SecurityScore}/100.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new AIPluginResult(ex, $"Input validation analysis failed: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines file type based on extension
|
|
/// </summary>
|
|
private string GetFileType(string extension)
|
|
{
|
|
return extension switch
|
|
{
|
|
".cs" => "C#",
|
|
".vb" => "VB.NET",
|
|
".js" => "JavaScript",
|
|
".ts" => "TypeScript",
|
|
".py" => "Python",
|
|
".java" => "Java",
|
|
".php" => "PHP",
|
|
".rb" => "Ruby",
|
|
".go" => "Go",
|
|
".html" => "HTML",
|
|
".aspx" => "ASP.NET",
|
|
".razor" => "Razor",
|
|
_ => "Unknown"
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Analyzes SQL injection protection patterns
|
|
/// </summary>
|
|
private async Task AnalyzeSqlInjectionProtection(string content, InputValidationResults results)
|
|
{
|
|
var sqlPatterns = ValidationPatterns.Where(p => p.Value.Type == "SQLInjection").ToList();
|
|
|
|
foreach (var pattern in sqlPatterns)
|
|
{
|
|
var matches = pattern.Value.Pattern.Matches(content);
|
|
foreach (Match match in matches)
|
|
{
|
|
// Check if this area has proper protection
|
|
if (!HasSqlProtection(content, match.Index))
|
|
{
|
|
results.ValidationIssues.Add(new ValidationIssue
|
|
{
|
|
Type = "SQL Injection Vulnerability",
|
|
Severity = pattern.Value.Severity,
|
|
Description = pattern.Value.Description,
|
|
LineNumber = GetLineNumber(content, match.Index),
|
|
Code = GetContextLines(content, match.Index, 2),
|
|
Recommendation = GetSqlInjectionRecommendation(pattern.Key)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for positive SQL protection patterns
|
|
CheckPositiveSqlPatterns(content, results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Analyzes XSS protection patterns
|
|
/// </summary>
|
|
private async Task AnalyzeXssProtection(string content, InputValidationResults results)
|
|
{
|
|
var xssPatterns = ValidationPatterns.Where(p => p.Value.Type == "XSS").ToList();
|
|
|
|
foreach (var pattern in xssPatterns)
|
|
{
|
|
var matches = pattern.Value.Pattern.Matches(content);
|
|
foreach (Match match in matches)
|
|
{
|
|
if (!HasXssProtection(content, match.Index))
|
|
{
|
|
results.ValidationIssues.Add(new ValidationIssue
|
|
{
|
|
Type = "Cross-Site Scripting (XSS) Vulnerability",
|
|
Severity = pattern.Value.Severity,
|
|
Description = pattern.Value.Description,
|
|
LineNumber = GetLineNumber(content, match.Index),
|
|
Code = GetContextLines(content, match.Index, 2),
|
|
Recommendation = GetXssRecommendation(pattern.Key)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for positive XSS protection patterns
|
|
CheckPositiveXssPatterns(content, results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Analyzes CSRF protection patterns
|
|
/// </summary>
|
|
private async Task AnalyzeCsrfProtection(string content, InputValidationResults results)
|
|
{
|
|
var csrfPatterns = ValidationPatterns.Where(p => p.Value.Type == "CSRF").ToList();
|
|
|
|
foreach (var pattern in csrfPatterns)
|
|
{
|
|
var matches = pattern.Value.Pattern.Matches(content);
|
|
foreach (Match match in matches)
|
|
{
|
|
results.MissingProtections.Add(new MissingProtection
|
|
{
|
|
Type = "CSRF Protection",
|
|
Description = pattern.Value.Description,
|
|
LineNumber = GetLineNumber(content, match.Index),
|
|
Code = GetContextLines(content, match.Index, 1),
|
|
Recommendation = "Add [ValidateAntiForgeryToken] attribute to POST actions and @Html.AntiForgeryToken() to forms"
|
|
});
|
|
}
|
|
}
|
|
|
|
// Check for existing CSRF protection
|
|
CheckCsrfProtectionMethod(content, results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Analyzes input sanitization patterns
|
|
/// </summary>
|
|
private async Task AnalyzeSanitizationMethod(string content, InputValidationResults results)
|
|
{
|
|
var sanitizationPatterns = ValidationPatterns.Where(p =>
|
|
p.Value.Type == "PathTraversal" ||
|
|
p.Value.Type == "CommandInjection" ||
|
|
p.Value.Type == "Deserialization" ||
|
|
p.Value.Type == "XXE").ToList();
|
|
|
|
foreach (var pattern in sanitizationPatterns)
|
|
{
|
|
var matches = pattern.Value.Pattern.Matches(content);
|
|
foreach (Match match in matches)
|
|
{
|
|
results.ValidationIssues.Add(new ValidationIssue
|
|
{
|
|
Type = pattern.Value.Type,
|
|
Severity = pattern.Value.Severity,
|
|
Description = pattern.Value.Description,
|
|
LineNumber = GetLineNumber(content, match.Index),
|
|
Code = GetContextLines(content, match.Index, 2),
|
|
Recommendation = GetSanitizationRecommendation(pattern.Key)
|
|
});
|
|
}
|
|
}
|
|
|
|
// Check for positive sanitization patterns
|
|
CheckSanitizationPatterns(content, results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Analyzes general validation patterns
|
|
/// </summary>
|
|
private async Task AnalyzeGeneralValidation(string content, InputValidationResults results)
|
|
{
|
|
var validationPatterns = ValidationPatterns.Where(p =>
|
|
p.Value.Type == "Validation" ||
|
|
p.Value.Type == "WeakValidation" ||
|
|
p.Value.Type == "RegexInjection").ToList();
|
|
|
|
foreach (var pattern in validationPatterns)
|
|
{
|
|
var matches = pattern.Value.Pattern.Matches(content);
|
|
foreach (Match match in matches)
|
|
{
|
|
results.ValidationIssues.Add(new ValidationIssue
|
|
{
|
|
Type = "Input Validation Issue",
|
|
Severity = pattern.Value.Severity,
|
|
Description = pattern.Value.Description,
|
|
LineNumber = GetLineNumber(content, match.Index),
|
|
Code = GetContextLines(content, match.Index, 1),
|
|
Recommendation = GetValidationRecommendation(pattern.Key)
|
|
});
|
|
}
|
|
}
|
|
|
|
// Check for data annotation usage
|
|
CheckDataAnnotations(content, results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if SQL protection is present near a vulnerability
|
|
/// </summary>
|
|
private bool HasSqlProtection(string content, int index)
|
|
{
|
|
var contextArea = GetContextArea(content, index, 300);
|
|
return GoodPatterns["parameterized_query"].IsMatch(contextArea) ||
|
|
GoodPatterns["entity_framework_linq"].IsMatch(contextArea);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if XSS protection is present near a vulnerability
|
|
/// </summary>
|
|
private bool HasXssProtection(string content, int index)
|
|
{
|
|
var contextArea = GetContextArea(content, index, 200);
|
|
return GoodPatterns["html_encode"].IsMatch(contextArea);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for positive SQL protection patterns
|
|
/// </summary>
|
|
private void CheckPositiveSqlPatterns(string content, InputValidationResults results)
|
|
{
|
|
if (GoodPatterns["parameterized_query"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses parameterized queries for SQL operations");
|
|
}
|
|
|
|
if (GoodPatterns["entity_framework_linq"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses Entity Framework LINQ queries (safe from SQL injection)");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for positive XSS protection patterns
|
|
/// </summary>
|
|
private void CheckPositiveXssPatterns(string content, InputValidationResults results)
|
|
{
|
|
if (GoodPatterns["html_encode"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses HTML encoding for output");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for CSRF protection implementation
|
|
/// </summary>
|
|
private void CheckCsrfProtectionMethod(string content, InputValidationResults results)
|
|
{
|
|
if (GoodPatterns["antiforgery_token"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Implements anti-forgery token protection");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for input sanitization patterns
|
|
/// </summary>
|
|
private void CheckSanitizationPatterns(string content, InputValidationResults results)
|
|
{
|
|
if (GoodPatterns["input_sanitization"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses input sanitization methods");
|
|
}
|
|
|
|
if (GoodPatterns["path_validation"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses path validation for file operations");
|
|
}
|
|
|
|
if (GoodPatterns["safe_deserialization"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses safe deserialization settings");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for data annotation usage
|
|
/// </summary>
|
|
private void CheckDataAnnotations(string content, InputValidationResults results)
|
|
{
|
|
if (GoodPatterns["data_annotations"].IsMatch(content))
|
|
{
|
|
results.GoodPractices.Add("Uses data annotations for model validation");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets context area around a position
|
|
/// </summary>
|
|
private string GetContextArea(string content, int index, int contextSize)
|
|
{
|
|
var start = Math.Max(0, index - contextSize);
|
|
var end = Math.Min(content.Length, index + contextSize);
|
|
return content.Substring(start, end - start);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets line number for a character index
|
|
/// </summary>
|
|
private int GetLineNumber(string content, int index)
|
|
{
|
|
return content.Take(index).Count(c => c == '\n') + 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets context lines around a match
|
|
/// </summary>
|
|
private string GetContextLines(string content, int index, int contextLines)
|
|
{
|
|
var lines = content.Split('\n');
|
|
var targetLine = GetLineNumber(content, index) - 1;
|
|
|
|
var startLine = Math.Max(0, targetLine - contextLines);
|
|
var endLine = Math.Min(lines.Length - 1, targetLine + contextLines);
|
|
|
|
var contextList = new List<string>();
|
|
for (int i = startLine; i <= endLine; i++)
|
|
{
|
|
var marker = i == targetLine ? ">>> " : " ";
|
|
contextList.Add($"{marker}{i + 1}: {lines[i]}");
|
|
}
|
|
|
|
return string.Join("\n", contextList);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets SQL injection recommendation
|
|
/// </summary>
|
|
private string GetSqlInjectionRecommendation(string patternKey)
|
|
{
|
|
return patternKey switch
|
|
{
|
|
"sql_raw_query" => "Use parameterized queries instead of string concatenation. Replace with SqlParameter or similar.",
|
|
"sql_format_string" => "Replace String.Format with parameterized queries using SqlParameter objects.",
|
|
"sql_interpolation" => "Avoid string interpolation in SQL queries. Use parameterized queries or Entity Framework LINQ.",
|
|
"entity_raw_sql" => "Use FromSqlInterpolated() or parameterized versions of raw SQL methods in Entity Framework.",
|
|
_ => "Use parameterized queries or ORM methods to prevent SQL injection attacks."
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets XSS recommendation
|
|
/// </summary>
|
|
private string GetXssRecommendation(string patternKey)
|
|
{
|
|
return patternKey switch
|
|
{
|
|
"innerHTML_assignment" => "Use textContent instead of innerHTML, or encode the content with Html.Encode().",
|
|
"document_write" => "Avoid document.write(). Use safer DOM manipulation methods and encode user input.",
|
|
"eval_usage" => "Never use eval() with user input. Use JSON.parse() for data or safer alternatives.",
|
|
"html_raw" => "Use Html.Encode() instead of Html.Raw() unless absolutely necessary and input is trusted.",
|
|
"response_write" => "Use Html.Encode() before writing to response to prevent XSS attacks.",
|
|
_ => "Encode all user input before output and use safe DOM manipulation methods."
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets sanitization recommendation
|
|
/// </summary>
|
|
private string GetSanitizationRecommendation(string patternKey)
|
|
{
|
|
return patternKey switch
|
|
{
|
|
"path_traversal" => "Validate and sanitize file paths. Use Path.GetFullPath() and check against allowed directories.",
|
|
"unsafe_file_access" => "Validate file paths and restrict access to allowed directories only.",
|
|
"process_start" => "Avoid executing processes with user input. If necessary, use allow-lists and input validation.",
|
|
"cmd_execution" => "Never execute commands with user input. Use safer alternatives or strict input validation.",
|
|
"unsafe_deserialization" => "Use safe deserialization settings and validate input types before deserialization.",
|
|
"xml_external_entities" => "Set XmlResolver to null and disable external entity processing in XML parsers.",
|
|
"regex_injection" => "Use static regex patterns or validate regex input against a safe pattern allow-list.",
|
|
_ => "Sanitize and validate all user input before processing."
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets validation recommendation
|
|
/// </summary>
|
|
private string GetValidationRecommendation(string patternKey)
|
|
{
|
|
return patternKey switch
|
|
{
|
|
"missing_validation" => "Add input validation using data annotations or custom validation logic.",
|
|
"direct_model_binding" => "Add validation attributes like [Required], [StringLength], etc. to model properties.",
|
|
"weak_email_validation" => "Use [EmailAddress] data annotation or a proper email validation library.",
|
|
"missing_length_check" => "Add length validation to prevent buffer overflow or DoS attacks.",
|
|
_ => "Implement proper input validation using data annotations and custom validation logic."
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates security score based on findings
|
|
/// </summary>
|
|
private int CalculateSecurityScore(InputValidationResults results)
|
|
{
|
|
var baseScore = 100;
|
|
var severityPenalties = new Dictionary<string, int>
|
|
{
|
|
["Critical"] = 25,
|
|
["High"] = 15,
|
|
["Medium"] = 8,
|
|
["Low"] = 3
|
|
};
|
|
|
|
// Deduct points for issues
|
|
foreach (var issue in results.ValidationIssues)
|
|
{
|
|
baseScore -= severityPenalties.GetValueOrDefault(issue.Severity, 5);
|
|
}
|
|
|
|
foreach (var protection in results.MissingProtections)
|
|
{
|
|
baseScore -= 10;
|
|
}
|
|
|
|
// Add points for good practices (up to 20 bonus points)
|
|
var bonusPoints = Math.Min(20, results.GoodPractices.Count * 5);
|
|
baseScore += bonusPoints;
|
|
|
|
return Math.Max(0, Math.Min(100, baseScore));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates security improvement suggestions
|
|
/// </summary>
|
|
private List<string> GenerateSecuritySuggestions(InputValidationResults results)
|
|
{
|
|
var suggestions = new List<string>();
|
|
|
|
// Critical issues first
|
|
var criticalIssues = results.ValidationIssues.Where(i => i.Severity == "Critical").ToList();
|
|
if (criticalIssues.Any())
|
|
{
|
|
suggestions.Add("🚨 **CRITICAL**: Address critical security vulnerabilities immediately:");
|
|
foreach (var issue in criticalIssues.Take(3))
|
|
{
|
|
suggestions.Add($" • Line {issue.LineNumber}: {issue.Description}");
|
|
}
|
|
}
|
|
|
|
// High severity issues
|
|
var highIssues = results.ValidationIssues.Where(i => i.Severity == "High").ToList();
|
|
if (highIssues.Any())
|
|
{
|
|
suggestions.Add("⚠️ **HIGH PRIORITY**: Fix high-severity vulnerabilities:");
|
|
suggestions.Add($" • {highIssues.Count} high-severity issues found");
|
|
suggestions.Add(" • Focus on SQL injection and XSS prevention");
|
|
}
|
|
|
|
// Missing protections
|
|
if (results.MissingProtections.Any())
|
|
{
|
|
suggestions.Add("🛡️ **MISSING PROTECTIONS**: Implement security measures:");
|
|
var protectionTypes = results.MissingProtections.GroupBy(p => p.Type).ToList();
|
|
foreach (var group in protectionTypes)
|
|
{
|
|
suggestions.Add($" • {group.Key}: {group.Count()} instances");
|
|
}
|
|
}
|
|
|
|
// General recommendations
|
|
suggestions.Add("📋 **GENERAL RECOMMENDATIONS**:");
|
|
suggestions.Add(" • Use parameterized queries for all database operations");
|
|
suggestions.Add(" • Implement input validation with data annotations");
|
|
suggestions.Add(" • Encode all output to prevent XSS attacks");
|
|
suggestions.Add(" • Add CSRF protection to state-changing operations");
|
|
suggestions.Add(" • Validate and sanitize file paths and external input");
|
|
|
|
// Positive reinforcement
|
|
if (results.GoodPractices.Any())
|
|
{
|
|
suggestions.Add("✅ **GOOD PRACTICES FOUND**:");
|
|
foreach (var practice in results.GoodPractices.Take(5))
|
|
{
|
|
suggestions.Add($" • {practice}");
|
|
}
|
|
}
|
|
|
|
// Score-based recommendations
|
|
if (results.SecurityScore >= 80)
|
|
{
|
|
suggestions.Add("🌟 **EXCELLENT**: Your code follows good security practices!");
|
|
}
|
|
else if (results.SecurityScore >= 60)
|
|
{
|
|
suggestions.Add("👍 **GOOD**: Address remaining issues to improve security posture");
|
|
}
|
|
else
|
|
{
|
|
suggestions.Add("⚡ **ACTION NEEDED**: Significant security improvements required");
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets list of files to analyze based on path
|
|
/// </summary>
|
|
private List<string> GetFilesToAnalyze(string path)
|
|
{
|
|
var files = new List<string>();
|
|
|
|
if (File.Exists(path))
|
|
{
|
|
files.Add(path);
|
|
}
|
|
else if (Directory.Exists(path))
|
|
{
|
|
// Focus on code files that likely contain validation logic
|
|
var extensions = new[] { "*.cs", "*.js", "*.ts", "*.py", "*.java", "*.php", "*.rb", "*.go" };
|
|
|
|
foreach (var extension in extensions)
|
|
{
|
|
files.AddRange(Directory.GetFiles(path, extension, SearchOption.AllDirectories));
|
|
}
|
|
|
|
// Filter out common excluded directories
|
|
var excludedDirs = new[] { "node_modules", "bin", "obj", ".git", ".vs", "packages", "target", "build" };
|
|
files = files.Where(f => !excludedDirs.Any(dir => f.Contains($"{System.IO.Path.DirectorySeparatorChar}{dir}{System.IO.Path.DirectorySeparatorChar}"))).ToList();
|
|
|
|
// Limit to reasonable number of files to avoid performance issues
|
|
files = files.Take(50).ToList();
|
|
}
|
|
|
|
return files;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Results of input validation analysis
|
|
/// </summary>
|
|
public class InputValidationResults
|
|
{
|
|
public string FilePath { get; set; }
|
|
public string FileName { get; set; }
|
|
public string FileType { get; set; }
|
|
public List<ValidationIssue> ValidationIssues { get; set; } = new List<ValidationIssue>();
|
|
public List<MissingProtection> MissingProtections { get; set; } = new List<MissingProtection>();
|
|
public List<string> GoodPractices { get; set; } = new List<string>();
|
|
public List<string> Suggestions { get; set; } = new List<string>();
|
|
public int SecurityScore { get; set; }
|
|
|
|
public int GetTotalIssues() => ValidationIssues.Count + MissingProtections.Count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a validation issue
|
|
/// </summary>
|
|
public class ValidationIssue
|
|
{
|
|
public string Type { get; set; }
|
|
public string Severity { get; set; }
|
|
public string Description { get; set; }
|
|
public int LineNumber { get; set; }
|
|
public string Code { get; set; }
|
|
public string Recommendation { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a missing protection
|
|
/// </summary>
|
|
public class MissingProtection
|
|
{
|
|
public string Type { get; set; }
|
|
public string Description { get; set; }
|
|
public int LineNumber { get; set; }
|
|
public string Code { get; set; }
|
|
public string Recommendation { get; set; }
|
|
}
|
|
} |