在哪里验证输入参数以防止 C# Web API 控制器或服务或存储库中的 SQL 注入?

Where to validate input parameters to prevent SQL injection in C# web API controller or service or repository?

提问人:jen 提问时间:9/8/2022 更新时间:9/10/2022 访问量:978

问:

我知道参数化查询足以防止 SQL 注入。验证输入参数是否也是好的做法?验证输入参数的好方法是什么,以及在哪里(控制器、服务、存储库)验证它们?

这是我的控制器方法:

public async Task<ActionResult<List<Level>>> GetLevelsAsync([FromRoute] string Code, string Year)
{
    int appId = IsoCode.FromName(Code).Id;
    var result = await _sampleService.GetLevelsAsync(appId, Year);
    return result;
}

这是我的服务方法:

public async Task<List<Level>> GetLevelsAsync(int appId, string year)
{
    if (string.IsNullOrWhiteSpace(year) == true)
        throw new ArgumentNullException(nameof(year));

    var result = await _sampleRepository.GetLevelsByYear(appId, year);
    return result;
}

这是我的存储库方法:

public async Task<List<Level>> GetLevelsByYear(int appId, string year)
{
    if (string.IsNullOrWhiteSpace(year))
        throw new ArgumentNullException(nameof(year));

    var result = new List<Level>();
    var parameters = new { AppId = appId, Year = year };
    string sql = @"
                SELECT * 
                FROM [Levels] as l, [LevelYears] as v 
                WHERE 
                    v.LevelId = l.Id AND l.Active = 1 AND l.AppId = @AppId AND v.Year = @Year
                ORDER BY v.Sort asc
        ";

    using (IDbConnection db = new SqlConnection(_settings.SqlServerConnString))
    {
        try
        {
            result = db.Query<Level>(sql, parameters).ToList();
        }
        catch (Exception e)
        {
            _logger.LogError(e, "Error querying levels by year", new { appId, year });
            throw;
        }
    }
    return result;
}
C# 核心 ASP.NET-CORE-WebAPI SQL注入 WebAPI

评论

0赞 Daevin 9/8/2022
就我个人而言,我认为在SQL级别失败之前验证输入可能是一种很好的做法。查看 NuGet 包。FluentValidation
1赞 Charlieface 9/9/2022
你不需要验证任何东西,这是不必要的。参数是不可注入的,除非错误地编译为动态 SQL
0赞 c-sharp-and-swiftui-devni 10/10/2023
就个人而言,拥有 sql 本身就是应用程序内部的 vinnerable

答:

4赞 Egret 9/10/2022 #1

验证是很好的防御性编码。一些开发人员(我敢肯定不是你)将数据库中的数据视为“可信数据”,并且没有正确利用编码或预处理语句,这可能导致后续问题,例如二阶 SQL 注入、存储的 XSS,甚至业务逻辑问题。

验证取决于上下文。正面验证(白名单验证)是最佳做法,但并非总是可行。一些例子:

  • 您通常可以检查特定值是否为一组已知值之一(白名单验证)
  • 如果字段应该是整数或日期,则可以验证此字段以确保它包含该数据类型(或者可能为 NULL)。
  • 您可以要求大多数字段具有最小和最大长度。
  • 应验证任何字符串是否仅包含有效的 字符进行编码(例如,没有无效的 UTF-8 序列,只有可打印的字符)——这通常可以在 WAF 或 servlet 过滤器中更普遍地完成

在哪里验证?当数据通过信任边界时,应始终进行验证 - 验证来自其他源的任何数据。验证应位于可能重用的层。在这种情况下,我建议在这种情况下在服务级别进行验证。