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:
@@ -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.
Reference in New Issue
Block a user