MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Security/InputValidationPlugin.cs

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; }
}
}