79 lines
3.1 KiB
C#
79 lines
3.1 KiB
C#
using System.Text.RegularExpressions;
|
|
|
|
namespace YY.Admin.Services.Service.EquipmentDb;
|
|
|
|
/// <summary>
|
|
/// 设备库 SQL 白名单:仅允许访问 MCS 中间表白名单表。
|
|
/// </summary>
|
|
public static class EquipmentDbWhitelist
|
|
{
|
|
private static readonly HashSet<string> AllowedTables = new(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
"MCSToMES_Alarm", "MCSToMES_MixAlarm", "MCSToMES_MixAct", "MCSToMES_Act_Mill", "MCSToMES_MixBatch",
|
|
"MCSToMES_MixCon", "MCSToMES_MixCurve", "MCSToMES_MixStep", "MCSToMES_MixWeight",
|
|
"MCSToMES_MixExePlan", "MCSToMES_BinToMater", "MCSToMES_AutoXLLog", "MCSToMES_CheckScaleLog",
|
|
"MESToMCS_Material", "MESToMCS_MixPlan", "MESToMCS_Recipe",
|
|
"MESToMCS_Recipe_MixStep", "MESToMCS_Recipe_Weight"
|
|
};
|
|
|
|
private static readonly Regex Dangerous = new(
|
|
@"\b(DROP|ALTER|TRUNCATE|EXEC|EXECUTE|xp_|sp_|INTO\s+OUTFILE|OPENROWSET|OPENDATASOURCE)\b",
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
private static readonly Regex TableRef = new(
|
|
@"\b(?:FROM|INTO|UPDATE|JOIN)\s+\[?(?<t>[A-Za-z0-9_]+)\]?",
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
public static bool IsAllowedTable(string? table)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(table))
|
|
{
|
|
return false;
|
|
}
|
|
return AllowedTables.Contains(table.Trim());
|
|
}
|
|
|
|
public static void ValidateSql(string? sql, string? tableHint = null)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(sql))
|
|
{
|
|
throw new InvalidOperationException("SQL 不能为空");
|
|
}
|
|
if (Dangerous.IsMatch(sql))
|
|
{
|
|
throw new InvalidOperationException("SQL 包含禁止关键字");
|
|
}
|
|
var trimmed = sql.TrimStart();
|
|
var isSelect = trimmed.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase);
|
|
var isInsert = trimmed.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase);
|
|
var isUpdate = trimmed.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase);
|
|
var isDelete = trimmed.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase);
|
|
if (!(isSelect || isInsert || isUpdate || isDelete))
|
|
{
|
|
throw new InvalidOperationException("仅允许 SELECT/INSERT/UPDATE/DELETE");
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(tableHint) && !IsAllowedTable(tableHint))
|
|
{
|
|
throw new InvalidOperationException($"表不在白名单: {tableHint}");
|
|
}
|
|
|
|
foreach (Match m in TableRef.Matches(sql))
|
|
{
|
|
var t = m.Groups["t"].Value;
|
|
if (string.Equals(t, "TOP", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(t, "SELECT", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(t, "SET", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(t, "VALUES", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(t, "WHERE", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
if (!IsAllowedTable(t))
|
|
{
|
|
throw new InvalidOperationException($"SQL 引用了未授权表: {t}");
|
|
}
|
|
}
|
|
}
|
|
}
|