9 Mayıs 2025

NPOI - Excel Macro Injection (Sanitizer)

 public static class IRowExtensions
{
    public static ICell GetCellAndSecure(this IRow row, int cellNum)
    {
        var cell = row.GetCell(cellNum);
        DataFormatter dataFormatter = new DataFormatter(CultureInfo.CurrentCulture);
        string cellValue = dataFormatter.FormatCellValue(cell) ?? string.Empty;
        if (!string.IsNullOrEmpty(cellValue) || IsMalicious(cellValue))
        {
            if (CrossSiteScriptingValidation.IsDangerousString(cellValue, out _))
            {
                throw new InvalidDataException("İzin verilmeyen içerik!");
            }
        }
        return cell;
    }

    private static readonly string[] blacklist = new[]
    {
        "cmd", "powershell", "wscript", "createobject", "getobject", "shell",
        "cmd|", "cmd /c", "cmd /k", "cscript", "vbscript", "activex", "winhttp",
        "msxml2.xmlhttp", "adodb.stream", "urlmon", "downloadfile", "deletefile",
        "openastextstream", "write", "javascript:", "document.write", "eval", "exec",
        "|''!A1", "| '/c", "shell.application", "htafile", "autoopen", "workbook_open"
    };

    private static bool IsMalicious(string input)
    {
        if (string.IsNullOrWhiteSpace(input))
            return false;
                       
        return (input.StartsWith("=") || input.StartsWith("+") || input.StartsWith("-") || input.StartsWith("@")) || blacklist.Any(keyword => input.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0);
    }

    public static void SetCellAndSecure(this ICell cell, string cellValue)
    {
        if (!string.IsNullOrEmpty(cellValue))
        {
            if (CrossSiteScriptingValidation.IsDangerousString(cellValue, out _) || IsMalicious(cellValue))
            {
                
                
                XSSFSheet xssfSheet = (XSSFSheet)(cell.Sheet);
                IDrawing drawing = xssfSheet.CreateDrawingPatriarch();
                IClientAnchor anchor = drawing.CreateAnchor(0, 0, 0, 0, cell.ColumnIndex, cell.RowIndex, cell.ColumnIndex + 2, cell.RowIndex + 2);

                IComment comment = drawing.CreateCellComment(anchor);
                comment.String = new XSSFRichTextString("Bu hücrede potansiyel zararlı bir formül vardı, metne çevrildi.");
                comment.Author = "Güvenlik Filtreleme Sistemi";
                comment.Visible = true;

                cell.CellComment = comment;

                cell.SetCellValue($"'{cellValue}");

                var sheetWarnings = cell.Sheet.Workbook.GetSheet("UYARILAR");
                if (sheetWarnings == null)
                {
                    sheetWarnings = cell.Sheet.Workbook.CreateSheet("UYARILAR");
                    var header = sheetWarnings.CreateRow(0);
                    header.CreateCell(0).SetCellValue("Hücre");
                    header.CreateCell(2).SetCellValue("Durum");
                }

                var lastIndex = sheetWarnings.LastRowNum + 1;
                var rowWarning = sheetWarnings.CreateRow(lastIndex);
                rowWarning.CreateCell(0).SetCellValue($"{cell.Address}");
                rowWarning.CreateCell(1).SetCellValue("Zararlı içerik tespit edildi ve nötralize edildi");


                var cellStyle = cell.Sheet.Workbook.CreateCellStyle();
                cellStyle.FillBackgroundColor = HSSFColor.Yellow.Index;
                cellStyle.FillForegroundColor = HSSFColor.Red.Index;
                cellStyle.FillPattern = FillPattern.SolidForeground;
                cell.CellStyle = cellStyle;
                //throw new InvalidDataException("İzin verilmeyen içerik!");
            }
        }
        cell.SetCellValue($"{cellValue}" ?? string.Empty);
    }


    public static ICell GetCellAndSecure(this IRow row, int cellNum, MissingCellPolicy policy)
    {
        var cell = row.GetCell(cellNum, policy);
        var cellValue = cell?.ToString() ?? string.Empty;
        if (!string.IsNullOrEmpty(cellValue))
        {
            if (CrossSiteScriptingValidation.IsDangerousString(cellValue, out _) || IsMalicious(cellValue))
            {
                throw new InvalidDataException("İzin verilmeyen içerik!");
            }
        }
        return cell;
    }

    public static string ToStringOrDefault(this ICell cell, string defaultValue = "")
    {
        var response = defaultValue;
        if (cell != null)
        {
            response = cell.ToString();
            if (response == null)
                response = defaultValue;
            response = response.Trim();
        }
        if (response.StartsWith("'") || response.StartsWith("‘"))
            response = response.Substring(1);

        return response;
    }
}