资讯动态

EF Core 安全实践指南:安全保证、敏感数据日志与 SQL 注入防护机制解析

发布时间:2026/9/14 12:18:10 来源:尧图企业网站定制
EF Core 安全实践指南安全保证、敏感数据日志与 SQL 注入防护机制解析【免费下载链接】efcoreEF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.项目地址: https://gitcode.com/GitHub_Trending/ef/efcore本文基于 EF Core 仓库中维护的官方安全文档docs/security.md系统梳理 Entity Framework 对外承诺的安全保证Security Guarantees与面向开发者的安全注意事项Security Notes并结合当前仓库源码逐一印证其落地方式从用户输入校验、数据存储权限边界到日志脱敏开关、LINQ 参数化与迁移 API 的注入风险帮助你在使用 EF Core 构建应用时明确框架替你做了什么以及必须由你自己做什么。文档定位两份职责一套原则docs/security.md 记录的是 EF Core及后续版本对外做出的安全保证以及开发者使用 EF 时应遵循的安全相关指导。它同时服务于两个目标设计、评审和验证 Entity Framework 本身确保框架的演进始终满足既定的安全原则帮助开发者写出安全的应用让使用者了解 EF 处理了哪些安全问题以及在哪些边界上安全责任落在应用代码一方。仓库中还有一份配套的 docs/threat_model.md从威胁建模视角补充了 EF 的安全假设。阅读本指南时可以将其与威胁模型文档对照理解本文回答EF 承诺不泄露什么、不防护什么威胁模型回答基于什么假设做这些承诺。需要说明的是原文档撰写时间较早其中部分 API 名称如IncludeSensitiveDataInLog标志、EF 中没有接收原始 SQL 的 API对应的是 EF 早期版本下文在逐条解读时均标注了其在当前 EF Core 源码中的对应实现与演进。用户输入注入防护不能替代业务校验安全注意事项校验用户输入EF 虽然提供了对 SQL 注入攻击的防护见后文关系型提供程序一节但它不对输入做任何通用校验。原文档给出的指导如果传入 API 的值、用于 LINQ 查询的值、赋给实体属性的值等来自不可信来源应按照应用自身的业务要求做相应的校验。原文档还特别强调了一个容易被忽视的场景凡是用用户输入来动态构造查询的情况都包含在内。即使用的是 LINQ只要接受用户输入来构建表达式Expression Tree就必须验证最终只能构造出预期的表达式。这一点在 EF Core 中同样成立Expression树是强类型对象表达式注入虽然不像字符串拼接 SQL 那样常见但通过用户可控字符串动态拼接属性名、筛选条件等模式常见于通用查询构造器、Specification 模式依然存在。从源码结构看EF Core 的 LINQ 管道src/EFCore/Query只负责把表达式树翻译成 SQL它无法区分开发者写的表达式与由用户输入拼出来的表达式因此表达式层面的白名单校验责任完全在应用侧。参数化与校验是两个层次需要区分两件事参数化解决值是否被当作代码执行的问题校验解决值是否符合业务语义的问题。EF 保证前者后者必须由应用完成。数据存储EF 本身不提供访问控制安全注意事项EF 依赖数据存储自身的安全机制Entity Framework 不实现任何安全功能它依赖底层数据存储根据你提供的连接信息给出相应的权限控制。原文档给出两条指导提供给 EF 的连接信息其权限应当只覆盖应用预期要执行的操作最小权限原则。如果应用中某些用户不应执行 EF 连接信息所允许的操作这种限制必须在应用逻辑中实现——EF 不会替你做行级/用户级的授权判断。安全注意事项保护连接信息EF 需要连接信息才能访问数据存储这些信息应保存在安全位置。原文档指导连接信息中会被传给 EF 的敏感部分如用户名和密码应存放在安全的位置如密钥管理设施、环境变量等而不是硬编码或提交到代码仓库。这两条注意事项的实质是EF 的安全边界止于 ADO.NET 连接层。连接字符串里写了什么权限EF 就能做什么框架自身没有任何沙箱或授权逻辑——这一立场也在文末Assumptions一节中被明确列为基本假设。开发期诊断组件不得在生产环境启用安全注意事项诊断组件仅供开发使用原文档针对Microsoft.AspNet.Diagnostics.Entity组件指出其中的Database Error Page数据库错误页与Migration Endpoint迁移端点仅应在应用开发阶段启用部署到生产环境后不应开启因为它们不实现任何安全控制Database Error Page会显示异常细节其中可能包含敏感信息如数据库对象名还会显示你源码及其引用库中 DbContext 与迁移类的详细信息并且允许直接对数据库应用迁移Migrations Endpoint允许对源码中及其引用库中的任意 context 发起迁移流程。原文档的指导只在开发应用时注册这些中间件最佳做法是利用 Startup.cs 中针对开发模式的附加配置能力将其限定在 Development 环境。如果确实选择在已部署的应用中启用这些组件你有责任自行实现相应的安全控制防止未授权访问。在历史演进上Microsoft.AspNet.Diagnostics.Entity是 ASP.NET 早期.NET Core 1.0 前后的独立诊断包当前 EF Core 仓库中已不再包含该组件按需触发迁移这一类能力如今由dotnet-ef命令行工具承担其命令实现位于 src/ef/Commands而dotnet-ef是构建期/运维期工具而非常驻中间件天然不存在生产环境暴露迁移端点的问题。但原文档的安全原则仍然成立任何能查看模型结构、触发数据库变更的调试入口都不应暴露在不受控的网络环境中。日志与异常三项安全保证及其边界原文档在这一节首先给出三个精确定义后续所有保证都建立在这套术语之上Logging日志指发送到注册到 EF 的ILogger实例Write方法的数据。其中也包括通过外部IServiceProvider如 ASP.NET 应用在 Startup 中注册的 ILogger注册给 EF 的实例。Message(s)消息指将被记录/显示/留存的字符串包括Exception.Message属性、Exception.ToString()方法返回值以及传给ILogger.Write的messageAction 返回的字符串。Application data应用数据来自数据存储或由最终用户提供数据。这类数据可能包含敏感信息用户名、信用卡号等例如查询结果、实体实例上存储的值、以及 LINQ 表达式中使用的常量值。安全保证消息中不包含数据存储凭据连接字符串或其他连接指定方式中的凭据永远不会出现在任何消息中。其他信息如数据库名可能会被记录。安全保证消息中默认不包含应用数据默认情况下消息不包含任何应用数据。这一保证的意义在于这些消息可能被显示给最终用户向终端用户显示异常虽不推荐但有意或无意的情况并不罕见也可能被写入到权限与数据库不一致的日志位置。警告一旦启用敏感数据日志标志原文档称为IncludeSensitiveDataInLog对应 EF 早期 issue #1374在当前 EF Core 中已演进为EnableSensitiveDataLogging选项该保证不再适用于日志消息。当前源码中的对应实现位于 DbContextOptionsBuilder.EnableSensitiveDataLoggingpublic new virtual DbContextOptionsBuilderTContext EnableSensitiveDataLogging(bool sensitiveDataLoggingEnabled true) (DbContextOptionsBuilderTContext)base.EnableSensitiveDataLogging(sensitiveDataLoggingEnabled);即默认值为true的参数是开关本身调用方显式传入true才会打开不配置时敏感数据日志保持关闭与默认消息不含应用数据的保证一致。安全保证日志状态中不包含应用数据传入ILogger.Write的状态state 与 exception 参数不包含指向应用数据的引用或包含可从中获取应用数据的对象。原因是某些日志框架会把 state 信息持久化到日志存储中如果其中夹带了实体引用敏感数据可能不知不觉地进入不受保护的位置。警告同样地启用敏感数据日志标志后该保证不再适用于日志状态。安全注意事项开启敏感数据日志标志的代价原文档对此的表述若启用该标志日志消息可能包含应用数据传给ILogger的 state 可能包含指向应用数据的引用。指导只有在应用数据不敏感、或你已经妥善保护了日志数据的去向时才启用该标志。原文档给出的具体例子开启该标志后EF 记录即将向数据库发送查询这类日志时会把查询模型作为 state 的一部分传给ILogger.Write这个 state 可以包含将进入查询的参数的引用而参数值可能来自用户提供的、用于 LINQ 查询Where子句的值。换言之打开开关后用户输入可能经由参数 → 日志 state这条链路进入日志系统——这正是该标志要求你确认日志存储位置是安全的的原因。安全注意事项异常对象本身可能持有应用数据虽然异常消息不含应用数据但异常对象可能提供指向实体或其他对象的引用从而间接访问到应用数据。原文档指导处理异常时应确保敏感数据被妥善保护。原文档以并发冲突为例数据库并发违规发生时EF 抛出DbUpdateConcurrencyException该异常类型通过StateEntries属性提供对涉及冲突的实体的更改跟踪信息的访问。在当前仓库中可以看到这一设计的延续DbUpdateConcurrencyException 提供了接收IReadOnlyListIUpdateEntry的构造函数把参与冲突的更新条目挂到异常对象上便于调用方定位是哪些实体、哪些属性导致了更新行数不匹配。使用这类信息做诊断是便利的但也要意识到把它直接序列化进对外响应或不受控的日志就等于把实体上的数据暴露了出去。安全注意事项消息可能包含模型/架构信息消息可能包含模型形状和数据存储架构的信息既包括 EF 显式抛出的异常也包括 EF 底层组件如 SqlClient抛出的异常。原文档指导始终用try/catch包裹 EF 操作并实现相应逻辑处理失败不要把异常消息直接显示给应用最终用户。原文档给了两个典型示例实体类型映射到数据库中不存在的表时SQL Server 抛出异常提示表不存在。该异常不由 EF 处理直接返回给执行 EF 操作的代码SqlException: Invalid object name Customer.模型中某实体类型既未配置键属性、也没有可被约定识别为键的属性时异常消息会包含该实体类型名ModelItemNotFoundException: The entity type MusicStore.Models.Album requires a key to be defined.两条示例分别展示了数据库侧对象名泄露与代码侧类型名泄露两种信息暴露面。架构名、表名、实体名泄露后攻击者可以更低成本地推断数据模型结构因此在生产环境中对最终用户应做统一的错误归一化处理。关系型提供程序参数化保证与原始 SQL 边界安全保证LINQ 查询使用参数化和转义LINQ 查询中提供的任何值都会被适当地参数化或转义以抵御 SQL 注入攻击。由于值可能来自应用最终用户这一点至关重要。原文档示例public IEnumerableCustomer FindCustomers(string lastName) { using (var context new CustomerContext()) { var customers context.Customers .Where(c c.LastName lastName) .ToList(); } }lastName可能来自最终用户、可能带有恶意输入因此它以参数形式传递最终生成的 SQL 为SELECT [c].[CustomerId], [c].[Name] FROM [Customer] AS [c] WHERE [c].[LastName] p0从源码结构看这一保证的落点在查询管道查询编译器将表达式树中的常量捕获为参数由 SQL 生成器如 QuerySqlGenerator统一输出pN形式的参数占位符而不是把值拼接进 SQL 文本。安全保证更新管线使用参数化和转义来自实例数据即存储在实体属性中的值的任何值都会被参数化或转义。这同样是为了防 SQL 注入尤其在值来自最终用户时。原文档示例public Customer CreateCustomer(string firstName, string lastName) { using (var context new CustomerContext()) { var customer new Customer { FirstName firstName, LastName lastName }; context.Customers.Add(customer); context.SaveChanges(); return customer; } }名字值以参数传递生成的 SQL 为INSERT INTO [Customer] ([FirstName], [LastName]) OUTPUT INSERTED.[CustomerId] VALUES (p0, p1)这两项保证合起来覆盖了数据的读与写两条主路径只要你的数据经由IQueryable查询或经变更跟踪的实体更新Add/Update/Delete SaveChanges流动值的注入面就被框架封闭了。安全注意事项原始 SQL 查询务必使用参数化原文档指出接收原始 SQL 字符串的 API 允许方便地以参数形式传值因此任何原始 SQL 查询/命令中使用的值都应参数化如果通过字符串拼接动态构造查询串的任意部分保护输入不被注入的责任由你承担。原文档还附了一段落到 ADO.NETDbCommand层面的示例public void MoveClients(string oldOwner, string newOwner) { using (var context new OrdersContext()) { var connection context.Database.AsRelational().Connection.DbConnection; var cmd connection.CreateCommand(); cmd.CommandText UPDATE [dbo].[Customer] SET [Owner] p0 WHERE [Owner] p1; cmd.Parameters.Add(new SqlParameter(p0, newOwner)); cmd.Parameters.Add(new SqlParameter(p1, oldOwner)); connection.Open(); cmd.ExecuteNonQuery(); connection.Close(); } }值得对照的一点是原文档写于EF 尚无接收原始 SQL 的 API的年代其示例因此直接下沉到 ADO.NET而当前 EF Core 的关系型 API 已提供参数化的原始 SQL 入口。例如 RelationalDatabaseFacadeExtensions.ExecuteSqlRaw 允许在调用时传入参数集合内部以参数绑定方式执行而不是把值拼进 SQL 文本。因此当前版本下的指导可以更新为优先使用 EF Core 提供的参数化原始 SQL APIExecuteSqlRaw/FromSqlRaw系列只有当必须用字符串插值构造时才退回到只把可信标识符拼入、值一律走参数的纪律。安全注意事项迁移 API 不为不可信输入设计迁移 API 的设计目标是接受编译进应用的、可信的值即迁移代码文件中的常量。大部分值会做适当转义但存在一些直通型API 不做任何校验或转义典型如Sql(string)方法与defaultValueSql参数。当前源码中可以看到这类直通参数的存在MigrationBuilder 的列操作方法将defaultValueSql列默认约束使用的 SQL 表达式原样存入DefaultValueSql后续 SQL 生成时直接输出——这正是pass-thru特性的实现形态。原文档指导迁移 API 不是为接受不可信来源如应用最终用户的输入而设计的。若确实把不可信输入传入迁移 API应自行校验以抵御 SQL 注入攻击。换句话说迁移代码应被视为应用的一部分而非数据流的一部分任何运行时用用户输入生成迁移 SQL的用法都超出了该 API 的安全设计边界。基本假设Assumptions原文档最后列出了三份安全承诺赖以成立的假设并在更新文档时应重新审视EF 程序集在安全方面不做任何特殊处理它就在调用方代码的安全上下文中运行。EF 不能做到调用方代码本身做不到的事EF 的所有 I/O 操作都复用现有 .NET API不自行实现任何协议、文件解析等命令行接口如迁移工具的状态输出使用标准ILogger功能并遵循本文档所述的内容边界。这三条假设解释了全文的承诺结构EF 把自己定位为透明中间层——不新增攻击面不解析新协议、不提升权限把安全责任清晰地切分为框架保证的参数化与脱敏和应用负责的输入校验与授权两半。安全要点速查类别性质结论 / 行动LINQ 查询、实体更新管线安全保证值一律参数化/转义注入面由框架封闭日志消息、日志状态安全保证默认不含应用数据凭据永不出现用户输入含动态构造表达式注意事项框架不做通用校验应用必须按业务校验数据存储授权、连接字符串保管注意事项最小权限连接 敏感信息入安全存储行级授权由应用实现EnableSensitiveDataLogging开启后注意事项消息与 state 可能含用户数据仅在数据不敏感或日志去向受控时开启异常对象如并发冲突异常携带的更新条目注意事项消息安全但对象可能持有实体引用勿直接外泄模型/架构信息出现在消息中注意事项try/catch包裹 EF 操作避免把原始异常展示给最终用户原始 SQL注意事项值必须参数化字符串拼接部分由应用负责迁移 APISql(string)、defaultValueSql等直通项注意事项只接受编译期可信输入不可信输入须自行校验按这份边界执行即可得到原文档承诺的完整安全姿态数据读写走参数化通道日志默认脱敏输入校验、最小权限连接与异常处理由应用补齐——框架与使用者各自守住自己那一半。【免费下载链接】efcoreEF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.项目地址: https://gitcode.com/GitHub_Trending/ef/efcore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价