安全框架:输入验证 | 缓解措施Security Frame: Input Validation | Mitigations
使用不受信任样式表对所有转换禁用 XSLT 脚本Disable XSLT scripting for all transforms using untrusted style sheets
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | XSLT 安全、XsltSettings.EnableScript 属性XSLT Security, XsltSettings.EnableScript Property |
步骤Steps | XSLT 支持使用 <msxml:script> 元素在样式表内编写脚本。XSLT supports scripting inside style sheets using the <msxml:script> element. 这样,便可以在 XSLT 转换中使用自定义函数。This allows custom functions to be used in an XSLT transformation. 该脚本在执行转换的进程的上下文中执行。The script is executed under the context of the process performing the transform. 在不受信任的环境中必须禁用 XSLT 脚本,防止执行不受信任的代码。XSLT script must be disabled when in an untrusted environment to prevent execution of untrusted code. 如果使用 .NET:XSLT 脚本默认已禁用;但是,必须确保未通过 XsltSettings.EnableScript 属性显式将它启用。If using .NET: XSLT scripting is disabled by default; however, you must ensure that it has not been explicitly enabled through the XsltSettings.EnableScript property. |
示例Example
XsltSettings settings = new XsltSettings();
settings.EnableScript = true; // WRONG: THIS SHOULD BE SET TO false
示例Example
如果使用的是 MSXML 6.0,XSLT 脚本默认已禁用;但是,必须确保未通过 XML DOM 对象属性 AllowXsltScript 显式将它启用。If you are using MSXML 6.0, XSLT scripting is disabled by default; however, you must ensure that it has not been explicitly enabled through the XML DOM object property AllowXsltScript.
doc.setProperty("AllowXsltScript", true); // WRONG: THIS SHOULD BE SET TO false
示例Example
如果使用 MSXML 5 或更低版本,XSLT 脚本默认已启用,必须显式将它禁用。If you are using MSXML 5 or below, XSLT scripting is enabled by default and you must explicitly disable it. 将 XML DOM 对象属性 AllowXsltScript 设置为 false。Set the XML DOM object property AllowXsltScript to false.
doc.setProperty("AllowXsltScript", false); // CORRECT. Setting to false disables XSLT scripting.
确保可能包含用户可控内容的每个页面能够选择不使用自动 MIME 探查Ensure that each page that could contain user controllable content opts out of automatic MIME sniffing
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | IE8 安全性第五部分 - 全面保护IE8 Security Part V - Comprehensive Protection |
步骤Steps | 对于可能包含用户可控内容的每个页面,必须使用 HTTP 标头 从 Web 服务器传送的每种类型的文件都有一个关联的 MIME 类型(也称为 content-type),该类型描述内容的性质(即,图像、文本、应用程序,等等)Each type of file delivered from a web server has an associated MIME type (also called a content-type) that describes the nature of the content (that is, image, text, application, etc.) X-Content-Type-Options 标头是一个 HTTP 标头,可让开发人员指定不应该对其内容使用 MIME 探查。The X-Content-Type-Options header is an HTTP header that allows developers to specify that their content should not be MIME-sniffed. 此标头旨在缓解 MIME 探查攻击。This header is designed to mitigate MIME-Sniffing attacks. Internet Explorer 8 (IE8) 中已添加对此标头的支持Support for this header was added in Internet Explorer 8 (IE8) 只有 Internet Explorer 8 (IE8) 的用户才能受益于 X-Content-Type-Options。Only users of Internet Explorer 8 (IE8) will benefit from X-Content-Type-Options. 以前的 Internet Explorer 版本目前不支持 X-Content-Type-Options 标头Previous versions of Internet Explorer do not currently respect the X-Content-Type-Options header Internet Explorer 8(和更高版本)是能够实现 MIME 探查选择退出功能的唯一主流浏览器。Internet Explorer 8 (and later) are the only major browsers to implement a MIME-sniffing opt-out feature. 如果其他主流浏览器(Firefox、Safari、Chrome)可实现类似功能,此项建议会更新,以包括这些浏览器的语法If and when other major browsers (Firefox, Safari, Chrome) implement similar features, this recommendation will be updated to include syntax for those browsers as well |
示例Example
若要针对应用程序中的所有页面全局启用所需的标头,可执行以下操作之一:To enable the required header globally for all pages in the application, you can do one of the following:
- 如果应用程序由 Internet Information Services (IIS) 7 托管,请在 web.config 文件中添加该标头。Add the header in the web.config file if the application is hosted by Internet Information Services (IIS) 7
<system.webServer>
<httpProtocol>
<customHeaders>
<add name=""X-Content-Type-Options"" value=""nosniff""/>
</customHeaders>
</httpProtocol>
</system.webServer>
- 通过全局 Application_BeginRequest 添加该标头Add the header through the global Application_BeginRequest
void Application_BeginRequest(object sender, EventArgs e)
{
this.Response.Headers[""X-Content-Type-Options""] = ""nosniff"";
}
- 实现自定义的 HTTP 模块Implement custom HTTP module
public class XContentTypeOptionsModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += newEventHandler(context_PreSendRequestHeaders);
}
#endregion
void context_PreSendRequestHeaders(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
if (application == null)
return;
if (application.Response.Headers[""X-Content-Type-Options ""] != null)
return;
application.Response.Headers.Add(""X-Content-Type-Options "", ""nosniff"");
}
}
- 对于特定的页面,只能通过将所需的标头添加到单个响应来启用该标头:You can enable the required header only for specific pages by adding it to individual responses:
this.Response.Headers[""X-Content-Type-Options""] = ""nosniff"";
强化或禁用 XML 实体解析Harden or Disable XML Entity Resolution
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | XML 实体扩展、XML 拒绝服务攻击和防护、MSXML 安全概述、有关保护 MSXML 代码的最佳做法、NSXMLParserDelegate 协议参考、解析外部引用XML Entity Expansion, XML Denial of Service Attacks and Defenses, MSXML Security Overview, Best Practices for Securing MSXML Code, NSXMLParserDelegate Protocol Reference, Resolving External References |
步骤Steps | 在 XML 中,有一项功能尽管未得到广泛使用,但可让 XML 分析器使用文档本身内部定义的或者外部源中定义的值来扩展宏实体。Although it is not widely used, there is a feature of XML that allows the XML parser to expand macro entities with values defined either within the document itself or from external sources. 例如,文档中可能定义了值为“Microsoft”的实体“companyname”,因此,每当文档中出现文本“&companyname;”时,该文本就自动被文本“Microsoft”替换。For example, the document might define an entity "companyname" with the value "Microsoft," so that every time the text "&companyname;" appears in the document, it is automatically replaced with the text Microsoft. 或者,文档中可能定义了实体“MSFTStock”,用于引用外部 Web 服务来提取当前的 Microsoft 股价。Or, the document might define an entity "MSFTStock" that references an external web service to fetch the current value of Microsoft stock. 因此,每当文档中出现“&MSFTStock;”时,该值就会自动被当前股价替换。Then any time "&MSFTStock;" appears in the document, it is automatically replaced with the current stock price. 但是,如果此功能使用不当,则可能会造成拒绝服务 (DoS) 攻击。However, this functionality can be abused to create denial of service (DoS) conditions. 攻击者可以嵌套多个实体来制造指数扩张式 XML 炸弹,耗尽系统中所有可用的内存。An attacker can nest multiple entities to create an exponential expansion XML bomb that consumes all available memory on the system. 或者,攻击者可以创建一个外部引用,流式传输无限数量的数据,或者只是将线程挂起。Alternatively, he can create an external reference that streams back an infinite amount of data or that simply hangs the thread. 因此,如果应用程序不使用内部和/或外部 XML 实体解析,则必须完全禁用该功能;或者,如果绝对有必要使用此功能,需手动限制应用程序执行实体解析时可以消耗的内存和时间。As a result, all teams must disable internal and/or external XML entity resolution entirely if their application does not use it, or manually limit the amount of memory and time that the application can consume for entity resolution if this functionality is absolutely necessary. 如果应用程序不需要实体解析,请禁用该功能。If entity resolution is not required by your application, then disable it. |
示例Example
对于 .NET Framework 代码,可使用以下方法:For .NET Framework code, you can use the following approaches:
XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);
// for .NET 4
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlReader reader = XmlReader.Create(stream, settings);
请注意,ProhibitDtd
在 XmlReaderSettings
中的默认值为 true,但在 XmlTextReader
中为 false。Note that the default value of ProhibitDtd
in XmlReaderSettings
is true, but in XmlTextReader
it is false. 如果使用 XmlReaderSettings,则不需要显式将 ProhibitDtd 设置为 true,但为安全起见,建议这样设置。If you are using XmlReaderSettings, you do not need to set ProhibitDtd to true explicitly, but it is recommended for safety sake that you do. 另请注意,XmlDocument 类默认允许实体解析。Also note that the XmlDocument class allows entity resolution by default.
示例Example
若要对 XmlDocuments 禁用实体解析,请使用 Load 方法的 XmlDocument.Load(XmlReader)
重载,并在 XmlReader 参数中设置相应的属性来禁用解析,如以下代码中所示:To disable entity resolution for XmlDocuments, use the XmlDocument.Load(XmlReader)
overload of the Load method and set the appropriate properties in the XmlReader argument to disable resolution, as illustrated in the following code:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
示例Example
如果无法对应用程序禁用实体解析,请根据应用程序的需要,将 XmlReaderSettings.MaxCharactersFromEntities 属性设置为某个合理值。If disabling entity resolution is not possible for your application, set the XmlReaderSettings.MaxCharactersFromEntities property to a reasonable value according to your application's needs. 这样可以限制潜在的指数扩张 DoS 攻击的影响。This will limit the impact of potential exponential expansion DoS attacks. 以下示例代码演示了此方法:The following code provides an example of this approach:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1000;
XmlReader reader = XmlReader.Create(stream, settings);
示例Example
如果需要解析内联实体但不需要解析外部实体,请将 XmlReaderSettings.XmlResolver 属性设置为 null。If you need to resolve inline entities but do not need to resolve external entities, set the XmlReaderSettings.XmlResolver property to null. 例如:For example:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1000;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);
请注意,在 MSXML6 中,ProhibitDTD 默认设置为 true(禁用 DTD 处理)。Note that in MSXML6, ProhibitDTD is set to true (disabling DTD processing) by default. 对于 Apple OSX/iOS 代码,可以使用两个 XML 分析器:NSXMLParser 和 libXML2。For Apple OSX/iOS code, there are two XML parsers you can use: NSXMLParser and libXML2.
使用 http.sys 的应用程序执行 URL 规范化验证Applications utilizing http.sys perform URL canonicalization verification
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 空值N/A |
步骤Steps | 使用 http.sys 的任何应用程序应遵循以下指导原则:Any application that uses http.sys should follow these guidelines:
|
确保接受用户的文件时实施适当的控制Ensure appropriate controls are in place when accepting files from users
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 不受限制的文件上传、文件签名表Unrestricted File Upload, File Signature Table |
步骤Steps | 上传的文件会给应用程序带来重大的风险。Uploaded files represent a significant risk to applications. 许多攻击的第一步就是在要攻击的系统中放入一些代码。The first step in many attacks is to get some code to the system to be attacked. 然后,攻击者只需找到一种执行该代码的方法。Then the attack only needs to find a way to get the code executed. 使用文件上传可以帮助攻击者实现这第一个步骤。Using a file upload helps the attacker accomplish the first step. 不受限制的文件上传的后果多种多样,包括完全接管系统、使文件系统或数据库过载、将攻击转移到后端系统,以及简单的篡改。The consequences of unrestricted file upload can vary, including complete system takeover, an overloaded file system or database, forwarding attacks to back-end systems, and simple defacement. 这种后果取决于应用程序对上传的文件的处理,尤其是该文件的存储位置。It depends on what the application does with the uploaded file and especially where it is stored. 服务器端缺少对文件上传的验证。Server side validation of file uploads is missing. 应该针对文件上传功能实施以下安全控制:Following security controls should be implemented for File Upload functionality:
|
示例Example
有关文件格式签名验证的最后一个要点,请参阅以下类的详细信息:For the last point regarding file format signature validation, refer to the class below for details:
private static Dictionary<string, List<byte[]>> fileSignature = new Dictionary<string, List<byte[]>>
{
{ ".DOC", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
{ ".DOCX", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } },
{ ".PDF", new List<byte[]> { new byte[] { 0x25, 0x50, 0x44, 0x46 } } },
{ ".ZIP", new List<byte[]>
{
new byte[] { 0x50, 0x4B, 0x03, 0x04 },
new byte[] { 0x50, 0x4B, 0x4C, 0x49, 0x54, 0x55 },
new byte[] { 0x50, 0x4B, 0x53, 0x70, 0x58 },
new byte[] { 0x50, 0x4B, 0x05, 0x06 },
new byte[] { 0x50, 0x4B, 0x07, 0x08 },
new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70 }
}
},
{ ".PNG", new List<byte[]> { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } },
{ ".JPG", new List<byte[]>
{
new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 }
}
},
{ ".JPEG", new List<byte[]>
{
new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 }
}
},
{ ".XLS", new List<byte[]>
{
new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 },
new byte[] { 0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00 },
new byte[] { 0xFD, 0xFF, 0xFF, 0xFF }
}
},
{ ".XLSX", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } },
{ ".GIF", new List<byte[]> { new byte[] { 0x47, 0x49, 0x46, 0x38 } } }
};
public static bool IsValidFileExtension(string fileName, byte[] fileData, byte[] allowedChars)
{
if (string.IsNullOrEmpty(fileName) || fileData == null || fileData.Length == 0)
{
return false;
}
bool flag = false;
string ext = Path.GetExtension(fileName);
if (string.IsNullOrEmpty(ext))
{
return false;
}
ext = ext.ToUpperInvariant();
if (ext.Equals(".TXT") || ext.Equals(".CSV") || ext.Equals(".PRN"))
{
foreach (byte b in fileData)
{
if (b > 0x7F)
{
if (allowedChars != null)
{
if (!allowedChars.Contains(b))
{
return false;
}
}
else
{
return false;
}
}
}
return true;
}
if (!fileSignature.ContainsKey(ext))
{
return true;
}
List<byte[]> sig = fileSignature[ext];
foreach (byte[] b in sig)
{
var curFileSig = new byte[b.Length];
Array.Copy(fileData, curFileSig, b.Length);
if (curFileSig.SequenceEqual(b))
{
flag = true;
break;
}
}
return flag;
}
确保在 Web 应用程序中使用类型安全的参数进行数据访问Ensure that type-safe parameters are used in Web Application for data access
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 空值N/A |
步骤Steps | 如果使用 Parameters 集合,SQL 会将输入视为文本值而不是可执行代码。If you use the Parameters collection, SQL treats the input is as a literal value rather then as executable code. 使用 Parameters 集合可针对输入数据实施类型和长度约束。The Parameters collection can be used to enforce type and length constraints on input data. 如果值超出范围,将触发异常。Values outside of the range trigger an exception. 如果不使用类型安全的 SQL 参数,攻击者可能会执行嵌入在未筛选输入中的注入式攻击。If type-safe SQL parameters are not used, attackers might be able to execute injection attacks that are embedded in the unfiltered input. 构造 SQL 查询时请使用类型安全的参数,避免未筛选的输入发生 SQL 注入式攻击。Use type safe parameters when constructing SQL queries to avoid possible SQL injection attacks that can occur with unfiltered input. 可在存储过程和动态 SQL 语句中使用类型安全的参数。You can use type safe parameters with stored procedures and with dynamic SQL statements. 数据库将参数视为文本值而不是可执行代码。Parameters are treated as literal values by the database and not as executable code. 此外,应检查参数的类型和长度。Parameters are also checked for type and length. |
示例Example
以下代码演示在调用存储过程时,如何对 SqlParameterCollection 使用类型安全的参数。The following code shows how to use type safe parameters with the SqlParameterCollection when calling a stored procedure.
using System.Data;
using System.Data.SqlClient;
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet userDataset = new DataSet();
SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure", connection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;
myCommand.Fill(userDataset);
}
在上面的代码示例中,输入值不能超过 11 个字符。In the preceding code example, the input value cannot be longer than 11 characters. 如果数据不符合该参数定义的类型或长度,SqlParameter 类将引发异常。If the data does not conform to the type or length defined by the parameter, the SqlParameter class throws an exception.
使用单独的模型绑定类或绑定筛选列表来防止 MVC 大规模分配漏洞Use separate model binding classes or binding filter lists to prevent MVC mass assignment vulnerability
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | MVC5、MVC6MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | 元数据属性、Metadata Attributes, 有关 ASP.NET MVC 中的大规模分配的完整指南、通过 MVC 开始使用 EFComplete Guide to Mass Assignment in ASP.NET MVC, Getting Started with EF using MVC |
步骤Steps |
|
在呈现之前为不受信任的 Web 输出编码Encode untrusted web output prior to rendering
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、Web 窗体、MVC5、MVC6Generic, Web Forms, MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | 如何在 ASP.NET 中防止跨站点脚本、跨站点脚本、XSS(跨站点脚本)预防速查表How to prevent Cross-site scripting in ASP.NET, Cross-site Scripting, XSS (Cross Site Scripting) Prevention Cheat Sheet |
步骤Steps | 跨站点脚本(通常缩写为 XSS)是针对联机服务或者使用 Web 输入的任何应用程序/组件的攻击向量。Cross-site scripting (commonly abbreviated as XSS) is an attack vector for online services or any application/component that consumes input from the web. 攻击者可能会利用 XSS 漏洞,通过有漏洞的 Web 应用程序在另一个用户的计算机上执行脚本。XSS vulnerabilities may allow an attacker to execute script on another user's machine through a vulnerable web application. 使用恶意脚本可以窃取 Cookie,或者通过 JavaScript 篡改受害者的计算机。Malicious scripts can be used to steal cookies and otherwise tamper with a victim's machine through JavaScript. 通过验证用户输入,确保在网页中呈现之前其格式正确并经过编码,可以阻止 XSS。XSS is prevented by validating user input, ensuring it is well formed and encoding before it is rendered in a web page. 可以使用 Web 保护库执行输入验证和输出编码。Input validation and output encoding can be done by using Web Protection Library. 对于托管代码(C#、VB.NET 等),可以根据显示用户输入的上下文,使用 Web 保护 (Anti-XSS) 库中一个或多个适当的编码方法:For Managed code (C#, VB.NET, etc.), use one or more appropriate encoding methods from the Web Protection (Anti-XSS) Library, depending on the context where the user input gets manifested: |
示例Example
* Encoder.HtmlEncode
* Encoder.HtmlAttributeEncode
* Encoder.JavaScriptEncode
* Encoder.UrlEncode
* Encoder.VisualBasicScriptEncode
* Encoder.XmlEncode
* Encoder.XmlAttributeEncode
* Encoder.CssEncode
* Encoder.LdapEncode
针对所有字符串类型的 Model 属性执行输入验证和筛选Perform input validation and filtering on all string type Model properties
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、MVC5、MVC6Generic, MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | 添加验证、验证 MVC 应用程序中的模型数据、ASP.NET MVC 应用程序指导原则Adding Validation, Validating Model Data in an MVC Application, Guiding Principles For Your ASP.NET MVC Applications |
步骤Steps | 在应用程序中使用所有输入参数之前必须验证这些参数,确保应用程序能够防御恶意用户输入的攻击。All the input parameters must be validated before they are used in the application to ensure that the application is safeguarded against malicious user inputs. 结合允许列表验证策略,在服务器端使用正则表达式验证来验证输入值。Validate the input values using regular expression validations on server side with a allowed list validation strategy. 传递给方法的未经净化的用户输入/参数可能会导致代码注入安全漏洞。Unsanitized user inputs / parameters passed to the methods can cause code injection vulnerabilities. 对于 Web 应用程序而言,入口点可能还包含窗体字段、QueryStrings、Cookie、HTTP 标头和 Web 服务参数。For web applications, entry points can also include form fields, QueryStrings, cookies, HTTP headers, and web service parameters. 必须针对模型绑定执行以下输入验证检查:The following input validation checks must be performed upon model binding:
|
应该针对接受所有字符的表单域(例如 RTF 编辑器)应用净化Sanitization should be applied on form fields that accept all characters, e.g, rich text editor
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 为不安全的输入编码、HTML 净化器Encode Unsafe Input, HTML Sanitizer |
步骤Steps | 找到想要使用的所有静态标记。Identify all static markup tags that you want to use. 常见的做法是限制对安全的 HTML 元素设置格式,例如 写入数据之前,对其进行 HTML 编码。Before writing the data, HTML-encode it. 这样就能使任何恶意脚本变得安全,因为它会作为文本而不是可执行代码进行处理。This makes any malicious script safe by causing it to be handled as text, not as executable code.
页入引用可通过设置 HtmlSanitizer 是一个 .NET 库,用于清理可能会导致 XSS 攻击的构造中的 HTML 片段和文档。HtmlSanitizer is a .NET library for cleaning HTML fragments and documents from constructs that can lead to XSS attacks. 它使用 AngleSharp 来分析、处理和呈现 HTML 与 CSS。It uses AngleSharp to parse, manipulate, and render HTML and CSS. 可在服务器端以 NuGet 包的形式安装 HtmlSanitizer,通过相关的 HTML 或 CSS 净化方法(如果适用)传递用户输入。HtmlSanitizer can be installed as a NuGet package, and the user input can be passed through relevant HTML or CSS sanitization methods, as applicable, on the server side. 请注意,只有在万不得已的情况下,才应考虑将净化用作安全控制措施。Please note that Sanitization as a security control should be considered only as a last option. 输入验证和输出编码被认为是更好的安全控制措施。Input validation and Output Encoding are considered better security controls. |
不要将 DOM 元素分配到没有内置编码的接收器Do not assign DOM elements to sinks that do not have inbuilt encoding
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 空值N/A |
步骤Steps | 许多 Javascript 函数默认不执行编码。Many javascript functions don't do encoding by default. 通过此类函数将不受信任的输入分配给 DOM 元素时,可能会导致执行跨站点脚本 (XSS)。When assigning untrusted input to DOM elements via such functions, may result in cross site script (XSS) executions. |
示例Example
下面是不安全做法的示例:Following are insecure examples:
document.getElementByID("div1").innerHtml = value;
$("#userName").html(res.Name);
return $('<div/>').html(value)
$('body').append(resHTML);
不要使用 innerHtml
,而是使用 innerText
。Don't use innerHtml
; instead use innerText
. 同样,不要使用 $("#elm").html()
,而是使用 $("#elm").text()
Similarly, instead of $("#elm").html()
, use $("#elm").text()
验证应用程序中的所有重定向是否闭合或安全执行Validate all redirects within the application are closed or done safely
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | OAuth 2.0 授权框架 - 开放重定向程序The OAuth 2.0 Authorization Framework - Open Redirectors |
步骤Steps | 要求重定向到用户提供的位置的应用程序设计必须将可能的重定向目标限制为站点或域的预定义“安全”列表。Application design requiring redirection to a user-supplied location must constrain the possible redirection targets to a predefined "safe" list of sites or domains. 应用程序中的所有重定向必须闭合且安全。All redirects in the application must be closed/safe. 为此,请按以下步骤操作:To do this:
|
针对 Controller 方法接受的所有字符串类型参数实施输入验证Implement input validation on all string type parameters accepted by Controller methods
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、MVC5、MVC6Generic, MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | 验证 MVC 应用程序中的模型数据、ASP.NET MVC 应用程序指导原则Validating Model Data in an MVC Application, Guiding Principles For Your ASP.NET MVC Applications |
步骤Steps | 对于只接受基元数据类型而不是模型作为参数的方法而言,应该使用正则表达式执行输入验证。For methods that just accept primitive data type, and not models as argument,input validation using Regular Expression should be done. 在此处,应该结合有效的正则表达式模式使用 Regex.IsMatch。Here Regex.IsMatch should be used with a valid regex pattern. 如果输入与指定的正则表达式不匹配,控制不应该继续,而是应该显示有关验证失败的充分警告。If the input doesn't match the specified Regular Expression, control should not proceed further, and an adequate warning regarding validation failure should be displayed. |
针对正则表达式处理设置超时上限,防止由于正则表达式错误而出现 DoSSet upper limit timeout for regular expression processing to prevent DoS due to bad regular expressions
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、Web 窗体、MVC5、MVC6Generic, Web Forms, MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | DefaultRegexMatchTimeout 属性DefaultRegexMatchTimeout Property |
步骤Steps | 为了确保拒绝服务攻击不会错误地创建正则表达式,从而导致大量的回溯,应设置全局默认超时。To ensure denial of service attacks against badly created regular expressions, that cause a lot of backtracking, set the global default timeout. 如果处理时间超过了定义的上限,将引发超时异常。If the processing time takes longer than the defined upper limit, it would throw a Timeout exception. 如果不进行任何配置,超时会是无限期。If nothing is configured, the timeout would be infinite. |
示例Example
例如,如果处理时间超过 5 秒,以下配置将引发 RegexMatchTimeoutException:For example, the following configuration will throw a RegexMatchTimeoutException, if the processing takes more than 5 seconds:
<httpRuntime targetFramework="4.5" defaultRegexMatchTimeout="00:00:05" />
避免在 Razor 视图中使用 Html.RawAvoid using Html.Raw in Razor views
标题Title | 详细信息Details |
---|---|
组件Component | Web 应用程序Web Application |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | MVC5、MVC6MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | 空值N/A |
步骤Step | ASP.NET 网页 (Razor) 执行自动 HTML 编码。ASP.NET WebPages (Razor) perform automatic HTML encoding. 嵌入式代码片段(@ 块)打印的所有字符串会自动进行 HTML 编码。All strings printed by embedded code nuggets (@ blocks) are automatically HTML-encoded. 但是,调用 HtmlHelper.Raw 方法时,将返回未经 HTML 编码的标记。However, when HtmlHelper.Raw Method is invoked, it returns markup that is not HTML encoded. 如果使用 Html.Raw() 帮助器方法,它会绕过 Razor 提供的自动编码保护。If Html.Raw() helper method is used, it bypasses the automatic encoding protection that Razor provides. |
示例Example
下面是不安全做法的示例:Following is an insecure example:
<div class="form-group">
@Html.Raw(Model.AccountConfirmText)
</div>
<div class="form-group">
@Html.Raw(Model.PaymentConfirmText)
</div>
</div>
除非需要显示标记,否则不要使用 Html.Raw()
。Do not use Html.Raw()
unless you need to display markup. 此方法不会隐式执行输出编码。This method does not perform output encoding implicitly. 应使用其他 ASP.NET 帮助器,例如 @Html.DisplayFor()
Use other ASP.NET helpers e.g., @Html.DisplayFor()
不要在存储过程中使用动态查询Do not use dynamic queries in stored procedures
标题Title | 详细信息Details |
---|---|
组件Component | 数据库Database |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 空值N/A |
步骤Steps | SQL 注入攻击利用输入验证中的漏洞在数据库中运行任意命令。A SQL injection attack exploits vulnerabilities in input validation to run arbitrary commands in the database. 如果应用程序使用输入来构造用于访问数据库的动态 SQL 语句,则可能会发生这种攻击。It can occur when your application uses input to construct dynamic SQL statements to access the database. 如果代码使用的存储过程是包含原始用户输入的传递字符串,则也可能会发生这种攻击。It can also occur if your code uses stored procedures that are passed strings that contain raw user input. 攻击者可以使用 SQL 注入式攻击在数据库中执行任意命令。Using the SQL injection attack, the attacker can execute arbitrary commands in the database. 所有 SQL 语句(包括存储过程中的 SQL 语句)必须参数化。All SQL statements (including the SQL statements in stored procedures) must be parameterized. 参数化 SQL 语句会正常接受包含对 SQL 具有特殊含义的字符(如单引号),因为这些字符已强类型化。Parameterized SQL statements will accept characters that have special meaning to SQL (like single quote) without problems because they are strongly typed. |
示例Example
下面是不安全的动态存储过程的示例:Following is an example of insecure dynamic Stored Procedure:
CREATE PROCEDURE [dbo].[uspGetProductsByCriteria]
(
@productName nvarchar(200) = NULL,
@startPrice float = NULL,
@endPrice float = NULL
)
AS
BEGIN
DECLARE @sql nvarchar(max)
SELECT @sql = ' SELECT ProductID, ProductName, Description, UnitPrice, ImagePath' +
' FROM dbo.Products WHERE 1 = 1 '
PRINT @sql
IF @productName IS NOT NULL
SELECT @sql = @sql + ' AND ProductName LIKE ''%' + @productName + '%'''
IF @startPrice IS NOT NULL
SELECT @sql = @sql + ' AND UnitPrice > ''' + CONVERT(VARCHAR(10),@startPrice) + ''''
IF @endPrice IS NOT NULL
SELECT @sql = @sql + ' AND UnitPrice < ''' + CONVERT(VARCHAR(10),@endPrice) + ''''
PRINT @sql
EXEC(@sql)
END
示例Example
下面是安全实现的同一个存储过程:Following is the same stored procedure implemented securely:
CREATE PROCEDURE [dbo].[uspGetProductsByCriteriaSecure]
(
@productName nvarchar(200) = NULL,
@startPrice float = NULL,
@endPrice float = NULL
)
AS
BEGIN
SELECT ProductID, ProductName, Description, UnitPrice, ImagePath
FROM dbo.Products where
(@productName IS NULL or ProductName like '%'+ @productName +'%')
AND
(@startPrice IS NULL or UnitPrice > @startPrice)
AND
(@endPrice IS NULL or UnitPrice < @endPrice)
END
确保针对 Web API 方法执行模型验证Ensure that model validation is done on Web API methods
标题Title | 详细信息Details |
---|---|
组件Component | Web APIWeb API |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | MVC5、MVC6MVC5, MVC6 |
属性Attributes | 空值N/A |
参考References | ASP.NET Web API 中的模型验证Model Validation in ASP.NET Web API |
步骤Steps | 当客户端向 Web API 发送数据时,必须在执行任何处理之前验证该数据。When a client sends data to a web API, it is mandatory to validate the data before doing any processing. 对于接受模型作为输入的 ASP.NET Web API 而言,请在模型中使用数据注释,以便针对模型属性设置验证规则。For ASP.NET Web APIs which accept models as input, use data annotations on models to set validation rules on the properties of the model. |
示例Example
以下代码演示了相同的操作:The following code demonstrates the same:
using System.ComponentModel.DataAnnotations;
namespace MyApi.Models
{
public class Product
{
public int Id { get; set; }
[Required]
[RegularExpression(@"^[a-zA-Z0-9]*$", ErrorMessage="Only alphanumeric characters are allowed.")]
public string Name { get; set; }
public decimal Price { get; set; }
[Range(0, 999)]
public double Weight { get; set; }
}
}
示例Example
在 API 控制器的操作方法中,必须显式验证模型的有效性,如下所示:In the action method of the API controllers, validity of the model has to be explicitly checked as shown below:
namespace MyApi.Controllers
{
public class ProductsController : ApiController
{
public HttpResponseMessage Post(Product product)
{
if (ModelState.IsValid)
{
// Do something with the product (not shown).
return new HttpResponseMessage(HttpStatusCode.OK);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
}
}
针对 Web API 方法接受的所有字符串类型参数实施输入验证Implement input validation on all string type parameters accepted by Web API methods
标题Title | 详细信息Details |
---|---|
组件Component | Web APIWeb API |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、MVC 5、MVC 6Generic, MVC 5, MVC 6 |
属性Attributes | 空值N/A |
参考References | 验证 MVC 应用程序中的模型数据、ASP.NET MVC 应用程序指导原则Validating Model Data in an MVC Application, Guiding Principles For Your ASP.NET MVC Applications |
步骤Steps | 对于只接受基元数据类型而不是模型作为参数的方法而言,应该使用正则表达式执行输入验证。For methods that just accept primitive data type, and not models as argument,input validation using Regular Expression should be done. 在此处,应该结合有效的正则表达式模式使用 Regex.IsMatch。Here Regex.IsMatch should be used with a valid regex pattern. 如果输入与指定的正则表达式不匹配,控制不应该继续,而是应该显示有关验证失败的充分警告。If the input doesn't match the specified Regular Expression, control should not proceed further, and an adequate warning regarding validation failure should be displayed. |
确保在 Web API 中使用类型安全的参数进行数据访问Ensure that type-safe parameters are used in Web API for data access
标题Title | 详细信息Details |
---|---|
组件Component | Web APIWeb API |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 空值N/A |
步骤Steps | 如果使用 Parameters 集合,SQL 会将输入视为文本值而不是可执行代码。If you use the Parameters collection, SQL treats the input is as a literal value rather then as executable code. 使用 Parameters 集合可针对输入数据实施类型和长度约束。The Parameters collection can be used to enforce type and length constraints on input data. 如果值超出范围,将触发异常。Values outside of the range trigger an exception. 如果不使用类型安全的 SQL 参数,攻击者可能会执行嵌入在未筛选输入中的注入式攻击。If type-safe SQL parameters are not used, attackers might be able to execute injection attacks that are embedded in the unfiltered input. 构造 SQL 查询时请使用类型安全的参数,避免未筛选的输入发生 SQL 注入式攻击。Use type safe parameters when constructing SQL queries to avoid possible SQL injection attacks that can occur with unfiltered input. 可在存储过程和动态 SQL 语句中使用类型安全的参数。You can use type safe parameters with stored procedures and with dynamic SQL statements. 数据库将参数视为文本值而不是可执行代码。Parameters are treated as literal values by the database and not as executable code. 此外,应检查参数的类型和长度。Parameters are also checked for type and length. |
示例Example
以下代码演示在调用存储过程时,如何对 SqlParameterCollection 使用类型安全的参数。The following code shows how to use type safe parameters with the SqlParameterCollection when calling a stored procedure.
using System.Data;
using System.Data.SqlClient;
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet userDataset = new DataSet();
SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure", connection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;
myCommand.Fill(userDataset);
}
在上面的代码示例中,输入值不能超过 11 个字符。In the preceding code example, the input value cannot be longer than 11 characters. 如果数据不符合该参数定义的类型或长度,SqlParameter 类将引发异常。If the data does not conform to the type or length defined by the parameter, the SqlParameter class throws an exception.
对 Cosmos DB 使用参数化 SQL 查询Use parameterized SQL queries for Cosmos DB
标题Title | 详细信息Details |
---|---|
组件Component | Azure Document DBAzure Document DB |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型Generic |
属性Attributes | 空值N/A |
参考References | 宣布推出 Azure Cosmos DB 中的 SQL 参数化Announcing SQL Parameterization in Azure Cosmos DB |
步骤Steps | 尽管 Azure Cosmos DB 仅支持只读查询,但如果查询是通过串联用户输入构造的,则仍有可能会发生 SQL 注入。Although Azure Cosmos DB only supports read-only queries, SQL injection is still possible if queries are constructed by concatenating with user input. 用户可能会通过编写恶意 SQL 查询,获取对同一集合中他们本应无权访问的数据的访问权限。It might be possible for a user to gain access to data they shouldn't be accessing within the same collection by crafting malicious SQL queries. 如果查询是基于用户输入构造的,请使用参数化 SQL 查询。Use parameterized SQL queries if queries are constructed based on user input. |
通过架构绑定执行 WCF 输入验证WCF Input validation through Schema binding
标题Title | 详细信息Details |
---|---|
组件Component | WCFWCF |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、NET Framework 3Generic, NET Framework 3 |
属性Attributes | 空值N/A |
参考References | MSDNMSDN |
步骤Steps | 缺少验证会导致不同类型的注入式攻击。Lack of validation leads to different type injection attacks. 消息验证相当于 WCF 应用程序的一道防线。Message validation represents one line of defense in the protection of your WCF application. 借助这种方式,可以使用架构来验证消息,防止 WCF 服务操作受到恶意客户端的攻击。With this approach, you validate messages using schemas to protect WCF service operations from attack by a malicious client. 验证客户端收到的所有消息,防止客户端受到恶意服务的攻击。Validate all messages received by the client to protect the client from attack by a malicious service. 当操作使用消息约定或数据约定时,可以使用消息验证来验证消息,而使用参数验证则做不到这一点。Message validation makes it possible to validate messages when operations consume message contracts or data contracts, which cannot be done using parameter validation. 使用消息验证可在架构中创建验证逻辑,从而提供更高的灵活性,缩短开发时间。Message validation allows you to create validation logic inside schemas, thereby providing more flexibility and reducing development time. 架构可在组织内的不同应用程序之间重复使用,为数据表示建立标准。Schemas can be reused across different applications inside the organization, creating standards for data representation. 此外,当操作使用涉及到表示业务逻辑的约定的更复杂数据类型时,可以使用消息验证来保护这些操作。Additionally, message validation allows you to protect operations when they consume more complex data types involving contracts representing business logic. 若要执行消息验证,首先需要构建一个架构来表示服务的操作,以及这些操作使用的数据类型。To perform message validation, you first build a schema that represents the operations of your service and the data types consumed by those operations. 然后创建一个 .NET 类,用于实现自定义客户端消息检查器和自定义调度程序消息检查器,以验证与服务之间相互发送/接收的消息。You then create a .NET class that implements a custom client message inspector and custom dispatcher message inspector to validate the messages sent/received to/from the service. 接下来,实现自定义的终结点行为,在客户端和服务中启用消息验证。Next, you implement a custom endpoint behavior to enable message validation on both the client and the service. 最后,在类中实现一个自定义配置元素,以便在服务或客户端的配置文件中公开扩展的自定义终结点行为Finally, you implement a custom configuration element on the class that allows you to expose the extended custom endpoint behavior in the configuration file of the service or the client" |
WCF - 通过参数检查器执行输入验证WCF- Input validation through Parameter Inspectors
标题Title | 详细信息Details |
---|---|
组件Component | WCFWCF |
SDL 阶段SDL Phase | 构建Build |
适用的技术Applicable Technologies | 泛型、NET Framework 3Generic, NET Framework 3 |
属性Attributes | 空值N/A |
参考References | MSDNMSDN |
步骤Steps | 输入和数据验证相当于 WCF 应用程序的一道重要防线。Input and data validation represents one important line of defense in the protection of your WCF application. 应该验证 WCF 服务操作中公开的所有参数,防止服务受到恶意客户端的攻击。You should validate all parameters exposed in WCF service operations to protect the service from attack by a malicious client. 反之,也应该验证客户端收到的所有返回值,防止客户端受到恶意服务的攻击Conversely, you should also validate all return values received by the client to protect the client from attack by a malicious service WCF 提供不同的扩展点用于通过创建自定义扩展来自定义 WCF 运行时行为。WCF provides different extensibility points that allow you to customize the WCF runtime behavior by creating custom extensions. 消息检查器和参数检查器是两个扩展机制,用于针对在客户端与服务之间传递的数据实施更大力度的控制。Message Inspectors and Parameter Inspectors are two extensibility mechanisms used to gain greater control over the data passing between a client and a service. 应该为输入验证使用参数检查器;仅当需要检查流入和流出服务的整个消息时,才使用消息检查器。You should use parameter inspectors for input validation and use message inspectors only when you need to inspect the entire message flowing in and out of a service. 若要执行输入验证,需要生成一个 .NET 类并实现自定义参数检查器,用于验证服务中操作上的参数。To perform input validation, you will build a .NET class and implement a custom parameter inspector in order to validate parameters on operations in your service. 然后,需要实现自定义的终结点行为,在客户端和服务中启用验证。You will then implement a custom endpoint behavior to enable validation on both the client and the service. 最后,需要在类中实现一个自定义配置元素,以便在服务或客户端的配置文件中公开扩展的自定义终结点行为Finally, you will implement a custom configuration element on the class that allows you to expose the extended custom endpoint behavior in the configuration file of the service or the client |