feat: aggiunto controllo di sicurezza per query custom SQL

- Implementato controllo di sicurezza per bloccare query non SELECT
- Aggiunta funzione IsSelectQuery() con validazione robusta
- Bloccate operazioni pericolose: INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, TRUNCATE, EXEC, etc.
- Implementata pulizia query per prevenire bypass tramite commenti SQL
- Aggiunto controllo per multiple statements separati da ;
- Aggiunto avviso di sicurezza nell'interfaccia utente
- Implementato logging di sicurezza per audit e debug
- Controllo applicato sia in validazione che in esecuzione per doppia protezione

Il sistema ora garantisce che solo query SELECT possano essere eseguite,
mantenendo la sicurezza del database e prevenendo operazioni di modifica non autorizzate.
This commit is contained in:
2025-06-29 20:49:32 +02:00
parent 04f0403f12
commit 06abaf40d4
2 changed files with 129 additions and 4 deletions
+129 -4
View File
@@ -106,10 +106,20 @@
<label class="form-label">Scrivi la tua query SELECT:</label> <label class="form-label">Scrivi la tua query SELECT:</label>
<textarea class="form-control" rows="6" placeholder="SELECT * FROM your_table WHERE condition..." <textarea class="form-control" rows="6" placeholder="SELECT * FROM your_table WHERE condition..."
@bind="customQuery" @bind:event="oninput"></textarea> @bind="customQuery" @bind:event="oninput"></textarea>
<small class="text-muted"> <div class="mt-2">
<i class="fas fa-info-circle"></i> <div class="alert alert-warning d-flex align-items-start" role="alert">
Scrivi una query SELECT personalizzata. La query verrà automaticamente ottimizzata per il trasferimento dati. <i class="fas fa-shield-alt me-2 mt-1"></i>
</small> <div>
<strong>Controlli di Sicurezza Attivi:</strong><br>
<small>
• Solo query <strong>SELECT</strong> sono permesse<br>
• Operazioni come INSERT, UPDATE, DELETE, DROP sono bloccate<br>
• Query multiple separate da ; non sono consentite<br>
• La query verrà automaticamente ottimizzata per il trasferimento dati
</small>
</div>
</div>
</div>
</div> </div>
<div class="mb-2"> <div class="mb-2">
@@ -2386,6 +2396,12 @@
throw new InvalidOperationException("Query custom non valida. Validare la query prima di procedere."); 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); var cleanQuery = CleanQuery(customQuery);
Logger.LogInformation("Esecuzione query custom per trasferimento dati: {Query}", cleanQuery); Logger.LogInformation("Esecuzione query custom per trasferimento dati: {Query}", cleanQuery);
@@ -2820,6 +2836,15 @@
return; 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; isValidatingQuery = true;
queryValidationMessage = ""; queryValidationMessage = "";
queryColumns.Clear(); queryColumns.Clear();
@@ -3031,4 +3056,104 @@
StateHasChanged(); StateHasChanged();
} }
/// <summary>
/// Verifica che la query sia una SELECT e non contenga operazioni pericolose
/// </summary>
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;
}
/// <summary>
/// Pulisce la query per il controllo di sicurezza rimuovendo commenti
/// </summary>
private string CleanQueryForSecurityCheck(string query)
{
if (string.IsNullOrEmpty(query))
return "";
var lines = query.Split('\n');
var cleanedLines = new List<string>();
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);
}
} }
Binary file not shown.