diff --git a/Data_Coupler/Pages/DataCoupler.razor b/Data_Coupler/Pages/DataCoupler.razor index 0221175..19b8d9e 100644 --- a/Data_Coupler/Pages/DataCoupler.razor +++ b/Data_Coupler/Pages/DataCoupler.razor @@ -106,10 +106,20 @@ - - - Scrivi una query SELECT personalizzata. La query verrà automaticamente ottimizzata per il trasferimento dati. - +
+ +
@@ -2386,6 +2396,12 @@ throw new InvalidOperationException("Query custom non valida. Validare la query prima di procedere."); } + // CONTROLLO DI SICUREZZA AGGIUNTIVO: Verifica che sia ancora una SELECT + if (!IsSelectQuery(customQuery)) + { + throw new InvalidOperationException("ERRORE DI SICUREZZA: Tentativo di eseguire una query non SELECT. Operazione bloccata per sicurezza."); + } + var cleanQuery = CleanQuery(customQuery); Logger.LogInformation("Esecuzione query custom per trasferimento dati: {Query}", cleanQuery); @@ -2820,6 +2836,15 @@ return; } + // CONTROLLO DI SICUREZZA: Verifica che sia una SELECT + if (!IsSelectQuery(customQuery)) + { + isQueryValid = false; + queryValidationMessage = "ERRORE DI SICUREZZA: Sono permesse solo query SELECT. Operazioni come INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, TRUNCATE non sono consentite."; + Logger.LogWarning("Tentativo di eseguire query non SELECT bloccato: {Query}", customQuery.Length > 100 ? customQuery.Substring(0, 100) + "..." : customQuery); + return; + } + isValidatingQuery = true; queryValidationMessage = ""; queryColumns.Clear(); @@ -3031,4 +3056,104 @@ StateHasChanged(); } + + /// + /// Verifica che la query sia una SELECT e non contenga operazioni pericolose + /// + private bool IsSelectQuery(string query) + { + if (string.IsNullOrWhiteSpace(query)) + return false; + + // Rimuovi commenti e normalizza la query + var cleanQuery = CleanQueryForSecurityCheck(query); + + // Lista delle operazioni pericolose che non sono permesse + var dangerousKeywords = new[] + { + "INSERT", "UPDATE", "DELETE", "DROP", "CREATE", "ALTER", + "TRUNCATE", "REPLACE", "MERGE", "EXEC", "EXECUTE", + "DECLARE", "SET", "GRANT", "REVOKE", "BACKUP", "RESTORE", + "SHUTDOWN", "KILL", "LOAD", "BULK", "OPENROWSET", "OPENDATASOURCE" + }; + + // Verifica che non contenga operazioni pericolose + foreach (var keyword in dangerousKeywords) + { + if (cleanQuery.Contains($" {keyword} ", StringComparison.OrdinalIgnoreCase) || + cleanQuery.StartsWith($"{keyword} ", StringComparison.OrdinalIgnoreCase) || + cleanQuery.Contains($";{keyword} ", StringComparison.OrdinalIgnoreCase) || + cleanQuery.Contains($"\n{keyword} ", StringComparison.OrdinalIgnoreCase) || + cleanQuery.Contains($"\r{keyword} ", StringComparison.OrdinalIgnoreCase)) + { + Logger.LogWarning("Query bloccata: contiene keyword pericolosa '{Keyword}' in query: {QueryStart}", + keyword, query.Length > 50 ? query.Substring(0, 50) + "..." : query); + return false; + } + } + + // Verifica che inizi con SELECT (permettendo spazi e commenti iniziali) + var trimmedQuery = cleanQuery.TrimStart(); + if (!trimmedQuery.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase)) + { + Logger.LogWarning("Query bloccata: non inizia con SELECT. Query: {QueryStart}", + query.Length > 50 ? query.Substring(0, 50) + "..." : query); + return false; + } + + // Verifica addizionale: non deve contenere punto e virgola seguito da altra query + var statements = cleanQuery.Split(';', StringSplitOptions.RemoveEmptyEntries); + if (statements.Length > 1) + { + // Se ci sono multiple statements, tutte devono essere SELECT o commenti vuoti + foreach (var statement in statements) + { + var trimmedStatement = statement.Trim(); + if (!string.IsNullOrEmpty(trimmedStatement) && + !trimmedStatement.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase)) + { + Logger.LogWarning("Query bloccata: contiene multiple statements non SELECT. Query: {QueryStart}", + query.Length > 50 ? query.Substring(0, 50) + "..." : query); + return false; + } + } + } + + return true; + } + + /// + /// Pulisce la query per il controllo di sicurezza rimuovendo commenti + /// + private string CleanQueryForSecurityCheck(string query) + { + if (string.IsNullOrEmpty(query)) + return ""; + + var lines = query.Split('\n'); + var cleanedLines = new List(); + + foreach (var line in lines) + { + var cleanedLine = line.Trim(); + + // Rimuovi commenti SQL (-- e /* */) + var dashCommentIndex = cleanedLine.IndexOf("--"); + if (dashCommentIndex >= 0) + { + cleanedLine = cleanedLine.Substring(0, dashCommentIndex).Trim(); + } + + // Gestione commenti multiline /* */ - implementazione base + cleanedLine = System.Text.RegularExpressions.Regex.Replace(cleanedLine, @"/\*.*?\*/", " ", + System.Text.RegularExpressions.RegexOptions.IgnoreCase); + + if (!string.IsNullOrWhiteSpace(cleanedLine)) + { + cleanedLines.Add(cleanedLine); + } + } + + return string.Join(" ", cleanedLines); + } } diff --git a/Data_Coupler/wwwroot/data/credentials.db-shm b/Data_Coupler/wwwroot/data/credentials.db-shm index 6262d13..c6bea81 100644 Binary files a/Data_Coupler/wwwroot/data/credentials.db-shm and b/Data_Coupler/wwwroot/data/credentials.db-shm differ