您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

安全框架:输入验证 | 缓解措施Security Frame: Input Validation | Mitigations

产品/服务Product/Service 文章Article
Web 应用程序Web Application
数据库Database
Web APIWeb API
Azure Document DBAzure Document DB
WCFWCF

使用不受信任样式表对所有转换禁用 XSLT 脚本Disable XSLT scripting for all transforms using untrusted style sheets

标题Title 详细信息Details
组件Component Web 应用程序Web Application
SDL 阶段SDL Phase BuildBuild
适用的技术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 BuildBuild
适用的技术Applicable Technologies 泛型Generic
属性Attributes 不可用N/A
参考References IE8 安全性第五部分 - 全面保护IE8 Security Part V - Comprehensive Protection
步骤Steps

对于可能包含用户可控内容的每个页面,必须使用 HTTP 标头 X-Content-Type-Options:nosniffFor each page that could contain user controllable content, you must use the HTTP Header X-Content-Type-Options:nosniff. 为了符合此要求,可以仅针对可能包含用户可控内容的页面逐页设置所需的标头,或者针对应用程序中的所有页面全局设置该标头。To comply with this requirement, you can either set the required header page by page for only those pages that might contain user-controllable content, or you can set it globally for all pages in the application.

从 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 BuildBuild
适用的技术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);

请注意,ProhibitDtdXmlReaderSettings 中的默认值为 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 BuildBuild
适用的技术Applicable Technologies 泛型Generic
属性Attributes 不可用N/A
参考References 不可用N/A
步骤Steps

使用 http.sys 的任何应用程序应遵循以下指导原则:Any application that uses http.sys should follow these guidelines:

  • 将 URL 的长度限制为不超过 16,384 个字符(ASCII 或 Unicode)。Limit the URL length to no more than 16,384 characters (ASCII or Unicode). 这是基于默认 Internet Information Services (IIS) 6 设置的绝对最大 URL 长度。This is the absolute maximum URL length based on the default Internet Information Services (IIS) 6 setting. 在网站中,应该尽可能使用短于此长度的 URL。Websites should strive for a length shorter than this if possible
  • 使用标准的 .NET Framework 文件 I/O 类(例如 FileStream),因为这些类可以利用 .NET FX 中的规范化规则Use the standard .NET Framework file I/O classes (such as FileStream) as these will take advantage of the canonicalization rules in the .NET FX
  • 显式构建已知文件名的允许列表Explicitly build an allow-list of known filenames
  • 显式拒绝你不会针对其提供 UrlScan reject 的已知文件类型:exe、bat、cmd、com、htw、ida、idq、htr、idc、shtm[l]、stm、printer、ini、pol、dat 文件Explicitly reject known filetypes you will not serve UrlScan rejects: exe, bat, cmd, com, htw, ida, idq, htr, idc, shtm[l], stm, printer, ini, pol, dat files
  • 捕获以下异常:Catch the following exceptions:
    • System.ArgumentException(针对设备名称)System.ArgumentException (for device names)
    • System.NotSupportedException(针对数据流)System.NotSupportedException (for data streams)
    • System.IO.FileNotFoundException(针对无效的转义文件名)System.IO.FileNotFoundException (for invalid escaped filenames)
    • System.IO.DirectoryNotFoundException(针对无效的转义目录)System.IO.DirectoryNotFoundException (for invalid escaped dirs)
  • 不要调用 Win32 文件 I/O API。Do not call out to Win32 file I/O APIs. 在 URL 无效时,应向用户正常返回 400 错误并记录实际错误。On an invalid URL gracefully return a 400 error to the user, and log the real error.

确保接受用户的文件时实施适当的控制Ensure appropriate controls are in place when accepting files from users

标题Title 详细信息Details
组件Component Web 应用程序Web Application
SDL 阶段SDL Phase BuildBuild
适用的技术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:

  • 文件扩展名检查(应该只接受有效的一组受允许文件类型)File Extension check (only a valid set of allowed file type should be accepted)
  • 文件大小上限Maximum file size limit
  • 不应将文件上传到 webroot;位置应是非系统驱动器上的某个目录File should not be uploaded to webroot; the location should be a directory on non-system drive
  • 应该遵守命名约定,使上传文件的名称具有某种随机性,防止文件覆盖Naming convention should be followed, such that the uploaded file name have some randomness, so as to prevent file overwrites
  • 将文件写入磁盘之前,应扫描它是否包含病毒Files should be scanned for anti-virus before writing to the disk
  • 确保验证文件名和其他任何元数据(例如文件路径)是否包含恶意字符Ensure that the file name and any other metadata (e.g., file path) are validated for malicious characters
  • 应检查文件格式签名,防止用户上传伪装的文件(例如,通过将扩展名更改为 txt 来上传 exe 文件)File format signature should be checked, to prevent a user from uploading a masqueraded file (e.g., uploading an exe file by changing extension to txt)

示例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 BuildBuild
适用的技术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 BuildBuild
适用的技术Applicable Technologies MVC5、MVC6MVC5, MVC6
属性Attributes 不可用N/A
参考References 元数据特性公共密钥安全漏洞和缓解措施有关 ASP.NET MVC 中的大规模分配的完整指南通过 MVC 开始使用 EFMetadata Attributes, Public Key Security Vulnerability And Mitigation, Complete Guide to Mass Assignment in ASP.NET MVC, Getting Started with EF using MVC
步骤Steps
  • 在什么情况下应该查找过度提交漏洞? - 在绑定用户输入中的模型类的任何位置,都可能存在过度提交漏洞。When should I look for over-posting vulnerabilities? - Over-posting vulnerabilities can occur any place you bind model classes from user input. MVC 等框架可在自定义 .NET 类中表示用户数据,包括普通旧 CLR 对象 (POCO)。Frameworks like MVC can represent user data in custom .NET classes, including Plain Old CLR Objects (POCOs). MVC 会在这些模型类中自动填充请求中的数据,提供一种便利的表示形式来处理用户输入。MVC automatically populates these model classes with data from the request, providing a convenient representation for dealing with user input. 如果这些类包含不应由用户设置的属性,应用程序将很容易遭到过度提交攻击,使用户能够控制应用程序永远不希望他们控制的数据。When these classes include properties that should not be set by the user, the application can be vulnerable to over-posting attacks, which allow user control of data that the application never intended. 与 MVC 模型绑定一样,数据库访问技术(例如,包括 Entity Framework 在内的对象/关系映射器)通常也支持使用 POCO 对象来表示数据库数据。Like MVC model binding, database access technologies such as object/relational mappers like Entity Framework often also support using POCO objects to represent database data. 使用这些数据模型类同样能够方便地处理数据库数据,就如同使用 MVC 处理用户输入一样。These data model classes provide the same convenience in dealing with database data as MVC does in dealing with user input. 由于 MVC 和数据库支持类似的模型(例如 POCO 对象),因此,似乎可以轻松地重复使用相同的类来实现这两种目的。Because both MVC and the database support similar models, like POCO objects, it seems easy to reuse the same classes for both purposes. 这种做法无法保留关注点分离,这是向模型绑定公共非预期属性,造成过度提交攻击的一个常见区域。This practice fails to preserve separation of concerns, and it is one common area where unintended properties are exposed to model binding, enabling over-posting attacks.
  • 为何不应使用未筛选的数据库模型类作为 MVC 操作的参数? - 因为 MVC 模型绑定会绑定该类中的任何内容。Why shouldn't I use my unfiltered database model classes as parameters to my MVC actions? - Because MVC model binding will bind anything in that class. 即使数据未显示在视图中,恶意用户也可以发送包含此数据的 HTTP 请求,而 MVC 会自然而然地绑定此请求,因为操作指出,数据库类就是它应该接受用户输入的数据形状。Even if the data does not appear in your view, a malicious user can send an HTTP request with this data included, and MVC will gladly bind it because your action says that database class is the shape of data it should accept for user input.
  • 为何应关心用于模型绑定的形状? - 结合过度扩散的模型使用 ASP.NET MVC 模型绑定会使应用程序曝露在过度提交攻击之下。Why should I care about the shape used for model binding? - Using ASP.NET MVC model binding with overly broad models exposes an application to over-posting attacks. 攻击者可能会利用过度提交来更改应用程序数据,使之超出开发人员的预期,例如,覆盖某个商品的价格,或者帐户的安全特权。Over-posting could enable attackers to change application data beyond what the developer intended, such as overriding the price for an item or the security privileges for an account. 应用程序应使用操作特定的绑定模型(或特定的受允许属性筛选列表)来提供显式约定,规定允许通过模型绑定提供哪些不受信任的输入。Applications should use action-specific binding models (or specific allowed property filter lists) to provide an explicit contract for what untrusted input to allow via model binding.
  • 是否存在只复制代码的单独绑定模型? - 没有,这是一个关注点分离的问题。Is having separate binding models just duplicating code? - No, it is a matter of separation of concerns. 如果在操作方法中重复使用数据库模型,则表示 HTTP 请求中的用户可以设置该类中的任何属性(或子属性)。If you reuse database models in action methods, you are saying any property (or sub-property) in that class can be set by the user in an HTTP request. 如果不希望 MVC 这样做,则需要使用筛选列表或单独的类形状来告知 MVC,可以通过用户输入提供哪些数据。If that is not what you want MVC to do, you need a filter list or a separate class shape to show MVC what data can come from user input instead.
  • 如果针对用户输入使用单独的绑定模型,是否需要复制所有数据批注特性? - 没有必要。If I have separate binding models for user input, do I have to duplicate all my data annotation attributes? - Not necessarily. 可在数据库模型类中使用 MetadataTypeAttribute 来链接到模型绑定类中的元数据。You can use MetadataTypeAttribute on the database model class to link to the metadata on a model binding class. 只需注意,MetadataTypeAttribute 所引用的类型必须是引用类型(可能包含更少或更多的属性)的子集。Just note that the type referenced by the MetadataTypeAttribute must be a subset of the referencing type (it can have fewer properties, but not more).
  • 在用户输入模型与数据库模型之间来回移动数据是个繁琐的过程。是否可以只使用反射来复制所有属性? - 可以。Moving data back and forth between user input models and database models is tedious. Can I just copy over all properties using reflection? - Yes. 在绑定模型中显示的属性无非就是你确定对于用户输入安全的属性。The only properties that appear in the binding models are the ones you have determined to be safe for user input. 没有安全方面的理由会阻止使用反射来复制这两个模型之间共有的所有属性。There is no security reason that prevents using reflection to copy over all properties that exist in common between these two models.
  • [Bind(Exclude ="…")] 怎么样?是否可以使用它来取代单独的绑定模型? - 不建议采用这种做法。What about [Bind(Exclude ="…")]. Can I use that instead of having separate binding models? - This approach is not recommended. 使用 [Bind(Exclude ="…")] 意味着默认情况下任何新属性都是可绑定的。Using [Bind(Exclude ="…")] means that any new property is bindable by default. 添加新属性后,记得执行一个额外的步骤来保持安全性,而不要采用默认的设计安全性。When a new property is added, there is an extra step to remember to keep things secure, rather than having the design be secure by default. 根据具体的开发人员,每次添加一个属性都要检查此列表是有风险的。Depending on the developer checking this list every time a property is added is risky.
  • [Bind(Include ="…")] 是否可用于“编辑”操作?- 不可以。Is [Bind(Include ="…")] useful for Edit operations? - No. [Bind(Include ="…")] 只适用于 INSERT 式操作(添加新数据)。[Bind(Include ="…")] is only suitable for INSERT-style operations (adding new data). 对于 UPDATE 式操作(修改现有数据),请使用另一种方式,例如,使用单独的绑定模型,或者将允许属性的显式列表传递给 UpdateModel 或 TryUpdateModel。For UPDATE-style operations (revising existing data), use another approach, like having separate binding models or passing an explicit list of allowed properties to UpdateModel or TryUpdateModel. 在“编辑”操作上添加 [Bind(Include ="…")] 属性意味着 MVC 将创建一个对象实例,并仅设置列出的属性,使所有其他属性保持默认值。Adding a [Bind(Include ="…")] attribute on an Edit operation means that MVC will create an object instance and set only the listed properties, leaving all others at their default values. 如果数据是持久保存的,将完全替换现有实体,将所有已省略属性的值重置为默认值。When the data is persisted, it will entirely replace the existing entity, resetting the values for any omitted properties to their defaults. 例如,如果在“编辑”操作的 [Bind(Include ="…")] 属性中省略了 IsAdmin,则通过此操作编辑其名称的任何用户都将重置为 IsAdmin = false(任何已编辑的用户都将丢失管理员 状态)。For example, if IsAdmin was omitted from a [Bind(Include ="…")] attribute on an Edit operation, any user whose name was edited via this action would be reset to IsAdmin = false (any edited user would lose administrator status). 如果想要防止对某些属性进行更新,请使用上述其他方式之一。If you want to prevent updates to certain properties, use one of the other approaches above. 请注意,某些版本的 MVC 工具会在“编辑”操作上生成带有 [Bind(Include ="…")] 的控制器类,并暗示从该列表中删除属性可防止过度发布攻击。Note that some versions of MVC tooling generate controller classes with [Bind(Include ="…")] on Edit actions and imply that removing a property from that list will prevent over-posting attacks. 但是,如上所述,这种方式无法按预期工作,而是将已省略属性中的任何数据重置为默认值。However, as described above, that approach does not work as intended and instead will reset any data in the omitted properties to their default values.
  • 对于“创建”操作,是否有任何使用 [Bind(Include ="…")] 而不是单独的绑定模型的注意事项?- 有。For Create operations, are there any caveats using [Bind(Include ="…")] rather than separate binding models? - Yes. 首先,这种方式不适用于 Edit 方案,它需要保留采用两种不同的方式来缓解所有过度提交漏洞。First this approach does not work for Edit scenarios, requiring maintaining two separate approaches for mitigating all over-posting vulnerabilities. 其次,单独的绑定模型强制分离用于用户输入的形状和用于持久性的形状之间的关注点,而 [Bind(Include ="…")] 做不到这一点。Second, separate binding models enforce separation of concerns between the shape used for user input and the shape used for persistence, something [Bind(Include ="…")] does not do. 第三,请注意 [Bind(Include ="…")] 只能处理顶级属性;不能仅允许属性中的部分子属性(例如“Details.Name”)。Third, note that [Bind(Include ="…")] can only handle top-level properties; you cannot allow only portions of sub-properties (such as "Details.Name") in the attribute. 最后,也许最重要的是,使用 [Bind(Include ="…")] 添加了一个额外步骤,只要该类用于模型绑定,就必须记住这一步骤。Finally, and perhaps most importantly, using [Bind(Include ="…")] adds an extra step that must be remembered any time the class is used for model binding. 如果新的操作方法直接绑定到数据类而忘记包含 [Bind(Include ="…")] 属性,则它可能容易受到过度发布攻击,因此 [Bind(Include ="…")] 方法默认情况下不太安全。If a new action method binds to the data class directly and forgets to include a [Bind(Include ="…")] attribute, it can be vulnerable to over-posting attacks, so the [Bind(Include ="…")] approach is somewhat less secure by default. 如果使用 [Bind(Include ="…")],请务必记住每次数据类作为操作方法参数出现时都指定它。If you use [Bind(Include ="…")], take care always to remember to specify it every time your data classes appear as action method parameters.
  • 对于“创建”操作,将 [Bind(Include ="…")] 属性放在模型类本身上怎么样?使用这种方式是否就不需要记得在每个操作方法中放置该特性? - 在某些情况下,这种方式是可行的。For Create operations, what about putting the [Bind(Include ="…")] attribute on the model class itself? Does not this approach avoid the need to remember putting the attribute on every action method? - This approach works in some cases. 在模型类型本身上(而不是在使用此类的操作参数上)使用 [Bind(Include ="…")],确实不需要记住在每个操作方法上包含 [Bind(Include ="…")] 属性。Using [Bind(Include ="…")] on the model type itself (rather than on action parameters using this class), does avoid the need to remember to include the [Bind(Include ="…")] attribute on every action method. 在类中直接使用该特性可以针对模型绑定目的,有效创建此类的独立外围应用。Using the attribute directly on the class effectively creates a separate surface area of this class for model binding purposes. 但是,这种方式只允许为每个模型类创建一个模型绑定形状。However, this approach only allows for one model binding shape per model class. 如果某个操作方法需要允许字段的模型绑定(例如,用于更新用户角色的仅限管理员的操作),而其他操作需要防止字段的模型绑定,则此方式不起作用。If one action method needs to allow model binding of a field (for example, an administrator-only action that updates user roles) and other actions need to prevent model binding of this field, this approach will not work. 每个类只能有一个模型绑定形状;如果不同的操作需要不同的模型绑定形状,就需要使用单独的模型绑定类或操作方法上的单独 [Bind(Include ="…")] 属性来表示这些单独的形状。Each class can only have one model binding shape; if different actions need different model binding shapes, they need to represent these separate shapes using either separate model binding classes or separate [Bind(Include ="…")] attributes on the action methods.
  • 什么是绑定模型?它们与视图模型一样吗? - 这是两个相关的概念。What are binding models? Are they the same thing as view models? - These are two related concepts. 术语“绑定模型”表示操作中使用的模型类是参数列表(从 MVC 模型绑定传递给操作方法的形状)。The term binding model refers to a model class used in an action's parameter list (the shape passed from MVC model binding to the action method). 术语“视图模型”表示从操作方法传递给视图的模型类。The term view model refers to a model class passed from an action method to a view. 我们经常使用视图特定的模型将数据从操作方法传递给视图。Using a view-specific model is a common approach for passing data from an action method to a view. 通常, 此形状也适用于模型绑定, 而术语视图模型可用于引用在这两个位置中使用的同一模型。Often, this shape is also suitable for model binding, and the term view model can be used to refer the same model used in both places. 为追求精确,本过程将专门讨论绑定模型并侧重于传递给操作的形状,这是有关大规模分配的一个要点。To be precise, this procedure talks specifically about binding models, focusing on the shape passed to the action, which is what matters for mass assignment purposes.

在呈现之前为不受信任的 Web 输出编码Encode untrusted web output prior to rendering

标题Title 详细信息Details
组件Component Web 应用程序Web Application
SDL 阶段SDL Phase BuildBuild
适用的技术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 保护 (防 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 BuildBuild
适用的技术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 whitelist 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:

  • 应该使用 RegularExpression 批注来批注模型属性,以便接受允许的字符,遵守最大允许长度The model properties should be annotated with RegularExpression annotation, for accepting allowed characters and maximum permissible length
  • 控制器方法应执行 ModelState 有效性检查The controller methods should perform ModelState validity

应该针对接受所有字符的表单域(例如 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 BuildBuild
适用的技术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 元素设置格式,例如 <b>(粗体)和 <i>(斜体)。A common practice is to restrict formatting to safe HTML elements, such as <b> (bold) and <i> (italic).

写入数据之前,对其进行 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.

  1. 通过在 @ 页面指令中添加 ValidateRequest="false" 特性来禁用 ASP.NET 请求验证Disable ASP.NET request validation by the adding the ValidateRequest="false" attribute to the @ Page directive
  2. 使用 HtmlEncode 方法为字符串输入编码Encode the string input with the HtmlEncode method
  3. 使用 StringBuilder 并调用其 Replace 方法,有选择性地删除想要允许的 HTML 元素中的编码Use a StringBuilder and call its Replace method to selectively remove the encoding on the HTML elements that you want to permit

页入引用可通过设置 ValidateRequest="false" 来禁用 ASP.NET 请求验证。The page-in the references disables ASP.NET request validation by setting ValidateRequest="false". 它会对输入进行 HTML 编码,并有选择性地允许 <b><i>。或者,也可以使用 .NET 库进行 HTML 净化。It HTML-encodes the input and selectively allows the <b> and <i> Alternatively, a .NET library for HTML sanitization may also be used.

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 BuildBuild
适用的技术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,而是使用 innerTextDon'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 BuildBuild
适用的技术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:

  • 识别所有重定向Identify all redirects
  • 针对每个重定向实施适当的缓解措施。Implement an appropriate mitigation for each redirect. 适当的缓解措施包括重定向允许列表或用户确认。Appropriate mitigations include redirect whitelist or user confirmation. 如果包含开放重定向漏洞的某个网站或服务使用 Facebook/OAuth/OpenID 标识提供者,攻击者可以窃取用户的登录令牌该模拟该用户。If a web site or service with an open redirect vulnerability uses Facebook/OAuth/OpenID identity providers, an attacker can steal a user's logon token and impersonate that user. 使用 RFC 6749“The OAuth 2.0 Authorization Framework”(OAuth 2.0 授权框架)第 10.15 部分“Open Redirects”(开放重定向)中所述的 OAuth 时会固有地存在此风险。同样,鱼叉网络钓鱼攻击可以使用开放重定向窃取用户的凭据This is an inherent risk when using OAuth, which is documented in RFC 6749 "The OAuth 2.0 Authorization Framework", Section 10.15 "Open Redirects" Similarly, users' credentials can be compromised by spear phishing attacks using open redirects

针对 Controller 方法接受的所有字符串类型参数实施输入验证Implement input validation on all string type parameters accepted by Controller methods

标题Title 详细信息Details
组件Component Web 应用程序Web Application
SDL 阶段SDL Phase BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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 BuildBuild
适用的技术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