.NET应用程序安全操作概述

介绍

此页面旨在为开发人员提供.NET 安全提示。

.NET Framework

.NET Framework 是 Microsoft 用于企业开发的主要平台。它是 ASP.NET,Windows 桌面应用程序,Windows Communication Foundation 服务,SharePoint,Visual Studio Tools for Office 和其他技术的支持 API。

译者注:本文中提供的许多操作指引在.NET Core 中也同样适用。

更新框架

Microsoft 通过 Windows Update 服务使.NET Framework 保持最新。开发人员通常不需要对框架运行单独的更新。可以在Windows Update[1]或 Windows 计算机上的 Windows Update 程序中访问Windows Update[2]

使用[NuGet](https://nuget.codeplex.com/wikipage?title=Getting Started&referringTitle=Home)可以使各个框架保持最新。当 Visual Studio 提示您进行更新时,请将其构建到您的生命周期中。

请记住,第三方库必须单独更新,并且并非所有人都使用 NuGet。例如,ELMAH 需要单独的更新工作。

安全公告

通过选择以下存储库中的“监视”按钮来接收安全通知:

.NET Core 安全公告[3]ASP.NET Core 和 Entity Framework 核心安全公告[4]

.NET Framework

.NET Framework 是一组 API,它们支持高级类型的系统,数据,图形,网络,文件处理以及在 Microsoft 生态系统中编写企业应用程序所需的大多数其余内容。它是一个几乎无处不在的库,在程序集级别上被强命名和版本化。

资料存取

使用参数化的 SQL[5]命令进行所有数据访问,无一例外。不要将SqlCommand[6]与由串联的 SQL String[7]组成的字符串参数一起使用。来自用户的白名单允许值。使用枚举,TryParse 或查找值来确保来自用户的数据符合预期。枚举仍然容易受到意外值的影响,因为.NET 仅验证是否成功转换为基础数据类型,默认情况下为整数。Enum.IsDefined[8]可以在定义的常量列表中验证输入值是否有效。在您选择的数据库中设置数据库用户时,请应用最小特权原则。数据库用户应该只能访问对用例有意义的项目。在使用实体框架[9]是一种非常有效的SQL 注入[10]防范机制。请记住,在 Entity Framework 中建立自己的关联查询与普通 SQL 查询一样容易受到 SQL 的影响使用 SQL Server 时,首选集成身份验证而[11]不是SQL 身份验证[12]对敏感数据(SQL Server 2016 和 SQL Azure)尽可能使用“始终加密”[13]

加密

永远不要写自己的加密。使用Windows 数据保护 API(DPAPI)[14]对敏感数据进行安全的本地存储。使用强大的哈希算法。在.NET(框架和内核)中,满足常规哈希要求的最强哈希算法是System.Security.Cryptography.SHA512[15]在.NET 框架中,最强的密码哈希算法是 PBKDF2,它实现为System.Security.Cryptography.Rfc2898DeriveBytes[16]在.NET Core 中,最强的密码哈希算法是 PBKDF2,它实现为Microsoft.AspNetCore.Cryptography.KeyDerivation.Pbkdf2[17],它比 Rfc2898DeriveBytes。当使用散列函数散列非唯一输入(例如密码)时,请在散列之前使用添加到原始值的盐值。确保您的应用程序或协议可以轻松支持将来更改密码算法。使用Nuget[18]可以使所有软件包保持最新状态。观看开发设置上的更新,并计划相应的应用程序更新。

一般

锁定配置文件。删除所有未使用的配置方面。加密 web.config

using 的敏感部分 aspnet_regiis -pe(命令行帮助[19])。对于“单击一次”应用程序,应将.Net Framework 升级为使用版本 4.6.2 以确保 TLS 1.1/1.2 支持。

ASP NET Web 表单指南

ASP.NET Web 窗体是用于.NET 框架的基于浏览器的原始应用程序开发 API,并且仍然是用于 Web 应用程序开发的最常见的企业平台。

始终使用HTTPS[20]对 cookie 和表单元素启用requireSSL[21],并在 web.config 中对 cookie 启用HttpOnly[22]实现customErrors[23]确保跟踪[24]已关闭。虽然 viewstate 并不总是适合于 Web 开发,但使用它可以缓解 CSRF。为了使 ViewState 免受 CSRF 攻击,您需要设置ViewStateUserKey[25]

protected override OnInit(EventArgs e) {
    base.OnInit(e);
    ViewStateUserKey = Session.SessionID;
}

如果您不使用 Viewstate,请使用双重提交 cookie 查找 ASP.NET Web 窗体默认模板的默认母版,以获取手动反 CSRF 令牌。

private const string AntiXsrfTokenKey = "__AntiXsrfToken";
private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
private string _antiXsrfTokenValue;
protected void Page_Init(object sender, EventArgs e)
{
    // The code below helps to protect against XSRF attacks
    var requestCookie = Request.Cookies[AntiXsrfTokenKey];
    Guid requestCookieGuidValue;
    if (requestCookie != null && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
    {
       // Use the Anti-XSRF token from the cookie
       _antiXsrfTokenValue = requestCookie.Value;
       Page.ViewStateUserKey = _antiXsrfTokenValue;
    }
    else
    {
       // Generate a new Anti-XSRF token and save to the cookie
       _antiXsrfTokenValue = Guid.NewGuid().ToString("N");
       Page.ViewStateUserKey = _antiXsrfTokenValue;
       var responseCookie = new HttpCookie(AntiXsrfTokenKey)
       {
          HttpOnly = true,
          Value = _antiXsrfTokenValue
       };
       if (FormsAuthentication.RequireSSL && Request.IsSecureConnection)
       {
          responseCookie.Secure = true;
       }
       Response.Cookies.Set(responseCookie);
    }
    Page.PreLoad += master_Page_PreLoad;
}
protected void master_Page_PreLoad(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
       // Set Anti-XSRF token
       ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
       ViewState[AntiXsrfUserNameKey] = Context.User.Identity.Name ?? String.Empty;
    }
    else
    {
       // Validate the Anti-XSRF token
if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue ||
          (string)ViewState[AntiXsrfUserNameKey] != (Context.User.Identity.Name ?? String.Empty))
       {
          throw new InvalidOperationException("Validation of Anti-XSRF token failed.");
       }
    }
}

考虑 IIS 中的HSTS[26]。有关步骤,请参见此处[27]建议您使用此 web.config 设置来处理 HSTS 等。

<?xml version="1.0" encoding="UTF-8"?>
 <configuration>
   <system.web>
     <httpRuntime enableVersionHeader="false"/>
   </system.web>
   <system.webServer>
     <security>
       <requestFiltering removeServerHeader="true" />
     </security>
     <staticContent>
       <clientCache cacheControlCustom="public"
            cacheControlMode="UseMaxAge"
            cacheControlMaxAge="1.00:00:00"
            setEtag="true" />
     </staticContent>
     <httpProtocol>
       <customHeaders>
         <add name="Content-Security-Policy"
            value="default-src 'none'; style-src 'self'; img-src 'self'; font-src 'self'" />
         <add name="X-Content-Type-Options" value="NOSNIFF" />
         <add name="X-Frame-Options" value="DENY" />
         <add name="X-Permitted-Cross-Domain-Policies" value="master-only"/>
         <add name="X-XSS-Protection" value="0"/>
         <remove name="X-Powered-By"/>
       </customHeaders>
     </httpProtocol>
     <rewrite>
       <rules>
         <rule name="Redirect to https">
           <match url="(.*)"/>
           <conditions>
             <add input="{HTTPS}" pattern="Off"/>
             <add input="{REQUEST_METHOD}" pattern="^get$|^head$" />
           </conditions>
           <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent"/>
         </rule>
       </rules>
       <outboundRules>
         <rule name="Add HSTS Header" enabled="true">
           <match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" />
           <conditions>
             <add input="{HTTPS}" pattern="on" ignoreCase="true" />
           </conditions>
           <action type="Rewrite" value="max-age=15768000" />
         </rule>
       </outboundRules>
     </rewrite>
   </system.webServer>
 </configuration>

删除版本头。

  • <httpRuntime enableVersionHeader=”false” />

同时删除服务器标头。

  • HttpContext.Current.Response.Headers.Remove(“Server”);

HTTP 验证和编码

不要在或页面设置中禁用validateRequest[28]web.config。此值在 ASP.NET 中启用了有限的 XSS 保护,应保留完整的位置,因为它提供了跨站点脚本的部分防护。除了内置保护之外,建议进行完整的请求验证。.NET Framework 的 4.5 版本包括AntiXssEncoder[29]库,该库具有用于防止 XSS 的全面输入编码库。用它。随时接受用户输入,将允许值列入白名单。使用Uri.IsWellFormedUriString[30]验证 URI 格式。

表格认证

尽可能使用 cookie 来保持持久性。Cookieless auth 将默认为UseDeviceProfile[31]不要信任会话或授权的持久性请求的 URI。它很容易伪造。将表单身份验证超时从默认的 20 分钟减少到适合您的应用程序的最短时间。如果使用了slideExpiration,[32]则此超时将在每次请求后重置,因此活动用户不会受到影响。如果不使用 HTTPS,[33]应该禁用slideExpiration[34]。考虑使用 HTTPS 禁用slideExpiration[35]始终实施适当的访问控制。将用户提供的用户名与进行比较 User.Identity.Name。检查角色 User.Identity.IsInRole。使用ASP.NET 成员资格提供程序和角色提供程序[36],但查看密码存储。默认存储使用 SHA-1 的单次迭代对密码进行哈希处理,这很弱。ASP.NET MVC4 模板使用ASP.NET 身份[37]而不是 ASP.NET 成员身份,并且 ASP.NET 身份默认使用 PBKDF2,这更好。查看 OWASP密码存储备忘单[38]以获取更多信息。明确授权资源请求。利用基于角色的授权 User.Identity.IsInRole。

ASP NET MVC 指南

ASP.NET MVC(模型–视图–控制器)是一种当代的 Web 应用程序框架,与 Web Forms 回发模型相比,它使用更加标准化的 HTTP 通信。

OWASP 2017 年十大最重要的威胁列出了当今世界上最普遍和最危险的网络安全威胁,并且每三年进行一次审查。

本部分基于此。保护 Web 应用程序安全的方法应该是从下面的最高威胁 A1 开始并逐步解决,这将确保花在安全性上的任何时间都可以最有效地花费,并且首先覆盖最重要的威胁,然后覆盖较小的威胁。在进入前十名之后,通常建议评估其他威胁或获得专业完成的渗透测试。

A1 注射

SQL 注入

应做:使用对象关系映射器(ORM)或存储过程是解决 SQL Injection 漏洞的最有效方法。

要做的事情:使用必须直接使用 SQL 查询的参数化查询。在这里[39]可以找到更多信息。

例如在实体框架中:

var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";
context.Database.ExecuteSqlCommand(
    sql,
    new SqlParameter("@FirstName", firstname),
    new SqlParameter("@Id", id));

请勿:在代码中的任何位置连接字符串,并在数据库中执行它们(称为动态 sql)。

注意:您仍然可能会意外地使用 ORM 或存储过程执行此操作,因此请检查所有位置。

例如

string strQry = "SELECT * FROM Users WHERE UserName='" + txtUser.Text + "' AND Password='"
                + txtPassword.Text + "'";
EXEC strQry // SQL Injection vulnerability!

要做:练习最小权限-使用具有执行该工作所需的最小权限集的帐户(即不是 sa 帐户)连接到数据库

操作系统注入

有关 OS 注入的信息可以在该备忘单[40]上找到。

应做:使用System.Diagnostics.Process.Start[41]调用底层 OS 函数。

例如

System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = "validatedCommand";
startInfo.Arguments = "validatedArg1 validatedArg2 validatedArg3";
process.StartInfo = startInfo;
process.Start();

应做:在所有用户提供的输入上使用白名单验证。输入验证可防止格式不正确的数据进入信息系统。有关更多信息,请参见输入验证备忘单[42]

例如,使用IPAddress.TryParse 方法[43]验证用户输入

//User input
string ipAddress = "127.0.0.1";
//check to make sure an ip address was provided
if (!string.IsNullOrEmpty(ipAddress))
{
 // Create an instance of IPAddress for the specified address string (in
 // dotted-quad, or colon-hexadecimal notation).
 if (IPAddress.TryParse(ipAddress, out var address))
 {
  // Display the address in standard notation.
  return address.ToString();
 }
 else
 {
  //ipAddress is not of type IPAddress
  ...
 }
    ...
}

LDAP 注入

专有名称中几乎可以使用任何字符。但是,某些字符必须使用反斜杠转义符进行转义。可以在LDAP 注入预防速查表上[44]找到一张表格,其中显示了应为 Active Directory 逃脱的字符。

注意:仅当空格字符是组件名称(例如通用名称)中的前导或尾随字符时,才必须转义。嵌入式空间不应逃脱。

这里[45]可以找到更多信息。

A2 身份验证失败

要做:使用ASP.net Core Identity[46]。默认情况下,ASP.net Core Identity 框架配置正确,在该框架中,它使用安全的密码哈希和单独的符号。身份使用 PBKDF2 哈希函数输入密码,并且每位用户都会生成随机的盐。

应做:设置安全密码策略

例如 ASP.net 核心身份

//startup.cs
services.Configure<IdentityOptions>(options =>
{
 // Password settings
 options.Password.RequireDigit = true;
 options.Password.RequiredLength = 8;
 options.Password.RequireNonAlphanumeric = true;
 options.Password.RequireUppercase = true;
 options.Password.RequireLowercase = true;
 options.Password.RequiredUniqueChars = 6;
 options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
 options.Lockout.MaxFailedAccessAttempts = 3;
 options.SignIn.RequireConfirmedEmail = true;
 options.User.RequireUniqueEmail = true;
});

要做的:设置 Cookie 政策

例如

//startup.cs
services.ConfigureApplicationCookie(options =>
{
 options.Cookie.HttpOnly = true;
 options.Cookie.Expiration = TimeSpan.FromHours(1)
 options.SlidingExpiration = true;
});

A3 敏感数据暴露

请勿:存储加密的密码[47]

请执行以下操作:使用强哈希值存储密码凭据。对于哈希,请参阅本节[48]

应做:以最小的复杂度来强制密码,使其在字典攻击中幸免,即较长的密码使用完整的字符集(数字,符号和字母)来增加熵。

要做的事情:使用强大的加密例程(例如 AES-512),其中需要将个人身份数据恢复为原始格式。保护加密密钥要比保护其他任何资产都重要,请查找更多有关静止存储加密密钥的信息[49]。应用以下测试:您是否愿意将数据保留在总线上的电子表格中,以供所有人阅读。假设攻击者可以直接访问您的数据库并进行相应的保护。在这里[50]可以找到更多信息。

要做:在整个站点上使用 TLS 1.2。获得免费的证书LetsEncrypt.org[51]

请勿:允许使用 SSL,现在已过时了[52]

请执行:拥有强大的 TLS 策略(请参阅SSL 最佳做法[53]),请尽可能使用 TLS 1.2。然后使用SSL Test[54]TestSSL[55]检查配置。

请执行以下操作:确保标头未公开有关您的应用程序的信息。请参阅HttpHeaders.cs[56]Dionach StripHeaders[57],通过 via web.config 或startup.cs[58]禁用:

有关传输层保护的更多信息,请参见此处[59]。例如 Web.config

<system.web>
    <httpRuntime enableVersionHeader="false"/>
</system.web>
<system.webServer>
    <security>
        <requestFiltering removeServerHeader="true" />
    </security>
    <httpProtocol>
        <customHeaders>
            <add name="X-Content-Type-Options" value="nosniff" />
            <add name="X-Frame-Options" value="DENY" />
            <add name="X-Permitted-Cross-Domain-Policies" value="master-only"/>
            <add name="X-XSS-Protection" value="0"/>
            <remove name="X-Powered-By"/>
        </customHeaders>
    </httpProtocol>
</system.webServer>

例如 Startup.cs

app.UseHsts(hsts => hsts.MaxAge(365).IncludeSubdomains());
app.UseXContentTypeOptions();
app.UseReferrerPolicy(opts => opts.NoReferrer());
app.UseXXssProtection(options => options.FilterDisabled());
app.UseXfo(options => options.Deny());
app.UseCsp(opts => opts
 .BlockAllMixedContent()
 .StyleSources(s => s.Self())
 .StyleSources(s => s.UnsafeInline())
 .FontSources(s => s.Self())
 .FormActions(s => s.Self())
 .FrameAncestors(s => s.Self())
 .ImageSources(s => s.Self())
 .ScriptSources(s => s.Self())
 );

有关标题的更多信息,请参见此处[60]

A4 XML 外部实体(XXE)

请参考 XXE 备忘单,以获取更多详细信息,可在此处[61]找到。

当 XML 解析未正确处理在 XML 有效负载的 doctype 中包含外部实体声明的用户输入时,就会发生 XXE 攻击。

以下是.NET 的三个最常见的XML 处理选项[62]

A5 损坏的访问控制

弱账户管理

确保通过 httpOnly 发送 cookie:

  • CookieHttpOnly = true,
  • 通过减少会话超时并消除滑动到期来减少会话被盗的时间:
  • ExpireTimeSpan = TimeSpan.FromMinutes(60),
  • SlidingExpiration = false

有关完整的启动代码段,请参见此处[63]

确保在生产环境中通过 HTTPS 发送 cookie。这应该在配置转换中强制执行:

<httpCookies requireSSL="true" xdt:Transform="SetAttributes(requireSSL)"/>
<authentication>
    <forms requireSSL="true" xdt:Transform="SetAttributes(requireSSL)"/>
</authentication>

通过限制请求来保护登录,注册和密码重置方法免受暴力攻击(请参见下面的代码),也可以考虑使用 ReCaptcha。

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[AllowXRequestsEveryXSecondsAttribute(Name = "LogOn",
Message = "You have performed this action more than {x} times in the last {n} seconds.",
Requests = 3, Seconds = 60)]
public async Task<ActionResult> LogOn(LogOnViewModel model, string returnUrl)

不要:进行自己的身份验证或会话管理,请使用.Net 提供的身份验证或会话管理

请勿:告诉某人该帐户是否存在登录,注册或密码重置的信息。说类似“用户名或密码不正确”或“如果此帐户存在,则重置令牌将发送到注册的电子邮件地址”之类的内容。这样可以防止帐户枚举。

无论在内容和行为上,无论是否存在该帐户,对用户的反馈都应该相同:例如,如果在真实帐户中的响应时间延长了 50%,则可以猜测和测试成员资格信息。

缺少功能级别的访问控制

应做:授权所有面向外部端点的用户。.NET 框架有很多方法可以授权用户,可以在方法级别使用它们:

[Authorize(Roles = "Admin")]
[HttpGet]
public ActionResult Index(int page = 1)

或更好,在控制器级别:

[Authorize]
public class UserController

您还可以使用.net 中的身份功能检查代码中的角色: System.Web.Security.Roles.IsUserInRole(userName, roleName)

你可以找到更多的信息,这里[64]的访问控制,并在这里[65]进行授权。

不安全的直接对象引用

当您拥有可由引用访问的资源(对象)(在下面的示例中是 id)时,您需要确保打算将用户放在那里

// Insecure
public ActionResult Edit(int id)
{
  var user = _context.Users.FirstOrDefault(e => e.Id == id);
  return View("Details", new UserViewModel(user);
}
// Secure
public ActionResult Edit(int id)
{
  var user = _context.Users.FirstOrDefault(e => e.Id == id);
  // Establish user has right to edit the details
  if (user.Id != _userIdentity.GetUserId())
  {
        HandleErrorInfo error = new HandleErrorInfo(
            new Exception("INFO: You do not have permission to edit these details"));
        return View("Error", error);
  }
  return View("Edit", new UserViewModel(user);
}

有关不安全的直接对象引用的更多信息,请参见此处[66]

A6 安全配置错误

调试和堆栈跟踪

确保调试和跟踪已在生产环境中关闭。可以使用 web.config 转换来强制执行:

<compilation xdt:Transform="RemoveAttributes(debug)" />
<trace enabled="false" xdt:Transform="Replace"/>

请勿:使用默认密码

做:(使用 TLS 时)将通过 Http 发出的请求重定向到 https:

例如 Global.asax.cs

protected void Application_BeginRequest()
{
    #if !DEBUG
    // SECURE: Ensure any request is returned over SSL/TLS in production
    if (!Request.IsLocal && !Context.Request.IsSecureConnection) {
        var redirect = Context.Request.Url.ToString()
                        .ToLower(CultureInfo.CurrentCulture)
                        .Replace("http:", "https:");
        Response.Redirect(redirect);
    }
    #endif
}

例如 Configure()中的 Startup.cs

  • app.UseHttpsRedirection();

跨站点伪造

请勿:在不验证防伪令牌(.NET[67] / .NET Core[68])的情况下发送敏感数据。

请执行:在每个 POST / PUT 请求中发送防伪令牌:

使用.NET FRAMEWORK

using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm",
                        @class = "pull-right" }))
{
    @Html.AntiForgeryToken()
    <ul class="nav nav-pills">
        <li role="presentation">
        Logged on as @User.Identity.Name
        </li>
        <li role="presentation">
        <a href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
        </li>
    </ul>
}

然后在方法或控制器级别进行验证:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()

确保令牌已完全删除,以使注销无效。

/// <summary>
/// SECURE: Remove any remaining cookies including Anti-CSRF cookie
/// </summary>
public void RemoveAntiForgeryCookie(Controller controller)
{
    string[] allCookies = controller.Request.Cookies.AllKeys;
    foreach (string cookie in allCookies)
    {
        if (controller.Response.Cookies[cookie] != null &&
            cookie == "__RequestVerificationToken")
        {
            controller.Response.Cookies[cookie].Expires = DateTime.Now.AddDays(-1);
        }
    }
}

使用.NET CORE 2.0 或更高版本

从.NET Core 2.0 开始,可以自动生成和验证防伪令牌[69]

如果您使用tag-helpers[70],这是大多数 Web 项目模板的默认设置,则所有表单都会自动发送防伪令牌。您可以通过检查主 _ViewImports.cshtml 文件是否包含以下内容来检查是否启用了标记辅助功能:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
IHtmlHelper.BeginForm 还会自动发送防伪令牌。

除非您使用 tag-helpers 或 IHtmlHelper.BeginForm,否则必须在表单上使用必需的帮助器,如下所示:

<form action="RelevantAction" >
@Html.AntiForgeryToken()
</form>

要自动验证除 GET,HEAD,OPTIONS 和 TRACE 之外的所有其他请求,您需要添加一个全局操作过滤器,该过滤器内部应具有AutoValidateAntiforgeryToken[71]属性,Startup.cs 如以下文章所述[72]

services.AddMvc(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

如果需要禁用控制器上特定方法的属性验证,可以将IgnoreAntiforgeryToken[73]属性添加到控制器方法(对于 MVC 控制器)或父类(对于 Razor 页面):

[IgnoreAntiforgeryToken]
[HttpDelete]
public IActionResult Delete()
[IgnoreAntiforgeryToken]
public class UnsafeModel : PageModel

如果您还需要验证 GET,HEAD,OPTIONS 或 TRACE-请求上的令牌,则可以将ValidateAntiforgeryToken[74]属性添加到控制器方法(对于 MVC 控制器)或父类(对于 Razor 页面):

[HttpGet]
[ValidateAntiforgeryToken]
public IActionResult DoSomethingDangerous()
[HttpGet]
[ValidateAntiforgeryToken]
public class SafeModel : PageModel

如果您不能使用全局操作过滤器,请将AutoValidateAntiforgeryToken[75]属性添加到控制器类或剃刀页面模型中:

[AutoValidateAntiforgeryToken]
public class UserController
[AutoValidateAntiforgeryToken]
public class SafeModel : PageModel

 将.NET CORE 2.0 或.NET FRAMEWORK 与 AJAX 一起使用

您将需要在 AJAX 请求上附加防伪令牌。

如果您在 ASP.NET Core MVC 视图中使用 jQuery,则可以使用以下代码段实现:

@inject  Microsoft.AspNetCore.Antiforgery.IAntiforgery antiforgeryProvider
$.ajax(
{
    type: "POST",
    url: '@Url.Action("Action", "Controller")',
    contentType: "application/x-www-form-urlencoded; charset=utf-8",
    data: {
        id: id,
        '__RequestVerificationToken': '@antiforgeryProvider.GetAndStoreTokens(this.Context).RequestToken'
    }
})

如果您使用的是.NET Framework,则可以在此处[76]找到一些代码段。

可以在此处[77]找到“跨站点请求伪造”的更多信息。

A7 跨站脚本(XSS)

不要:信任用户发送给您的任何数据,更喜欢白名单(始终安全)而不是黑名单

您可以使用 MVC3 对所有 HTML 内容进行编码,无论 HTML,javascript,CSS,LDAP 等是否使用 Microsoft AntiXSS 库都可以对所有内容进行正确编码:

  • Install-Package AntiXSS
  • 然后在配置中设置:
<system.web>
<httpRuntime targetFramework="4.5"
enableVersionHeader="false"
encoderType="Microsoft.Security.Application.AntiXssEncoder, AntiXssLibrary"
maxRequestLength="4096" />
</system.web>

请勿:使用[AllowHTML]属性或帮助程序类,@Html.Raw 除非您真的知道要写入浏览器的内容是安全的并且已被正确转义。

请执行以下操作:启用内容安全策略[78],这将阻止您的页面访问其不应该访问的资产(例如恶意脚本):

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Content-Security-Policy"
                value="default-src 'none'; style-src 'self'; img-src 'self';
                font-src 'self'; script-src 'self'" />

可以在此处[79]找到有关跨站点脚本的更多信息。

A8 不安全的反序列化

有关不安全反序列化的信息可以在此备忘单[80]上找到。

不要:接受来自不受信任来源的序列化对象

要做:验证用户输入恶意用户能够使用 Cookie 之类的对象插入恶意信息来更改用户角色。在某些情况下,黑客可以使用上一个会话中预先存在或缓存的密码哈希将其特权提升为管理员权限。

应做:防止域对象的反序列化

请执行:以有限的访问权限运行反序列化代码如果反序列化的敌对对象试图启动系统进程或访问服务器或主机 OS 中的资源,则将拒绝访问该对象,并且将引发权限标志,以便系统管理员被告知服务器上的任何异常活动。

可以在这里找到更多信息:反序列化备忘单[81]

A9 使用具有已知漏洞的组件

要做的:用最新的补丁更新.Net 框架

要做:使您的NuGet[82]软件包保持最新,许多将包含其自身的漏洞。

要做:作为构建过程的一部分,对您的应用程序运行OWASP Dependency Checker,[83]并对任何高级漏洞进行处理。

A10 记录和监控不足

请执行以下操作:确保可以使用足够的用户上下文记录所有登录,访问控制失败和服务器端输入验证失败,以识别可疑或恶意帐户。

应做:建立有效的监视和警报,以便及时发现可疑活动并做出响应。

请勿:记录一般错误消息,例如:csharp Log.Error(“Error was thrown”);记录引起错误的堆栈跟踪,错误消息和用户 ID。

请勿:记录敏感数据,例如用户的密码。

记录中

在该备忘单[84]上可以找到要收集的日志以及有关日志的更多信息。

.NET Core 带有一个 LoggerFactory,位于 Microsoft.Extensions.Logging 中。有关 ILogger 的更多信息,请参见此处[85]

如何记录来自的所有错误 Startup.cs,以便在引发错误时都会记录该错误。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
 if (env.IsDevelopment())
 {
  _isDevelopment = true;
  app.UseDeveloperExceptionPage();
 }
 //Log all errors in the application
 app.UseExceptionHandler(errorApp =>
 {
  errorApp.Run(async context =>
  {
      var errorFeature = context.Features.Get<IExceptionHandlerFeature>();
      var exception = errorFeature.Error;
      Log.Error(String.Format("Stacktrace of error: {0}",exception.StackTrace.ToString()));
  });
 });
        app.UseAuthentication();
            app.UseMvc();
        }
}

例如,注入到类构造函数中,这使得编写单元测试更加简单。建议使用依赖注入(例如 MVC 控制器)创建类的实例。以下示例显示了所有未成功登录尝试的日志记录。

public class AccountsController : Controller
{
        private ILogger _Logger;
        public AccountsController( ILogger logger)
        {
            _Logger = logger;
        }
 [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Login(LoginViewModel model)
        {
            if (ModelState.IsValid)
            {
                var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
                if (result.Succeeded)
                {
   //Log all successful log in attempts
   Log.Information(String.Format("User: {0}, Successfully Logged in", model.Email));
   //Code for successful login
  }
  else
  {
   //Log all incorrect log in attempts
   Log.Information(String.Format("User: {0}, Incorrect Password", model.Email));
  }
 }
 ...

ILogger 的日志记录级别按重要性从高到低的顺序列出如下:

监控方式

监视使我们能够通过关键性能指标来验证正在运行的系统的性能和运行状况。

在.NET 中,添加监视功能的绝佳选择是Application Insights[86]

可以在此处[87]找到有关日志记录和监视的更多信息。

OWASP 2013

以下是 OWASP 2017 中未讨论的漏洞

A10 未经验证的重定向和转发

Mvc 3 模板中引入了针对此问题的保护措施。这是代码:

public async Task<ActionResult> LogOn(LogOnViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var logonResult = await _userManager.TryLogOnAsync(model.UserName, model.Password);
        if (logonResult.Success)
        {
            await _userManager.LogOnAsync(logonResult.UserName, model.RememberMe);  
            return RedirectToLocal(returnUrl);
...
private ActionResult RedirectToLocal(string returnUrl)
{
    if (Url.IsLocalUrl(returnUrl))
    {
        return Redirect(returnUrl);
    }
    else
    {
        return RedirectToAction("Landing", "Account");
    }
}

其他建议:

为防止 Clickjacking 和中间人攻击而捕获初始的非 TLS 请求,请设置 X-Frame-Options 和 Strict-Transport-Security(HSTS)标头。完整细节在这里[88]防止从未来过您网站的用户遭受中间人攻击。注册以获取HSTS 预载[89]维护 Web API 服务的安全测试和分析。它们隐藏在 MEV 站点内部,并且是攻击者将发现的站点的公共部分。所有 MVC 指南和许多 WCF 指南都适用于 Web API。未经验证的重定向和转发备忘单[90]

更多信息:

有关上述所有内容的更多信息,以及合并到具有增强的安全性基准的示例 MVC5 应用程序中的代码示例,请转到Security Essentials Baseline 项目。[91]

XAML 指导

在您的应用程序的 Internet 区域安全性约束内工作。使用 ClickOnce 部署。要增强权限,请在运行时使用权限提升或在安装时使用可信应用程序部署。

Windows 表单指导

尽可能使用部分信任。部分受信任的 Windows 应用程序可减少应用程序的攻击面。管理您的应用必须使用的权限列表以及可能使用的权限列表,然后在运行时声明性地请求这些权限。使用 ClickOnce 部署。要增强权限,请在运行时使用权限提升或在安装时使用可信应用程序部署。

WCF 指导

请记住,在 RESTful 服务中传递请求的唯一安全方法是通过 HTTP POST,和 TLS enabled。GETs 在中可见,querystring 缺少 TLS 意味着可以拦截该正文。避免使用BasicHttpBinding[92]。它没有默认的安全配置。请改用WSHttpBinding[93]至少使用两种安全模式进行绑定。消息安全性包括标头中的安全性规定。传输安全性意味着使用 SSL。TransportWithMessageCredential[94]结合了两者。用诸如ZAP 之[95]类的模糊测试您的 WCF 实现。

References

[1] Windows Update: http://windowsupdate.microsoft.com/
[2] Windows Update: http://windowsupdate.microsoft.com/
[3] .NET Core 安全公告: https://github.com/dotnet/announcements/issues?q=is%3Aopen+is%3Aissue+label%3ASecurity
[4] ASP.NET Core 和 Entity Framework 核心安全公告: https://github.com/aspnet/Announcements/issues?q=is%3Aopen+is%3Aissue+label%3ASecurity
[5] 参数化的 SQL: https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.prepare?view=netframework-4.7.2
[6] SqlCommand: https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand
[7] 串联的 SQL String: https://docs.microsoft.com/en-gb/visualstudio/code-quality/ca2100-review-sql-queries-for-security-vulnerabilities?view=vs-2017
[8] Enum.IsDefined: https://docs.microsoft.com/en-us/dotnet/api/system.enum.isdefined
[9] 实体框架: https://docs.microsoft.com/en-us/ef/
[10] SQL 注入: https://owasp.org/www-community/attacks/SQL_Injection
[11] 集成身份验证而: https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/using-integrated-authentication?view=sql-server-2017
[12] SQL 身份验证: https://docs.microsoft.com/en-us/sql/relational-databases/security/choose-an-authentication-mode?view=sql-server-2017#connecting-through-sql-server-authentication
[13] 始终加密”: https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-database-engine
[14] Windows 数据保护 API(DPAPI): https://docs.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection
[15] System.Security.Cryptography.SHA512: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.sha512
[16] System.Security.Cryptography.Rfc2898DeriveBytes: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes
[17] Microsoft.AspNetCore.Cryptography.KeyDerivation.Pbkdf2: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing
[18] Nuget: https://docs.microsoft.com/en-us/nuget/
[19] 命令行帮助: https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-2.0/k6h9cz8h(v=vs.80)
[20] HTTPS: https://support.microsoft.com/kb/324069
[21] requireSSL: https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.httpcookiessection.requiressl
[22] HttpOnly: https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.httpcookiessection.httponlycookies
[23] customErrors: https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.customerror
[24] 跟踪: http://www.iis.net/configreference/system.webserver/tracing
[25] ViewStateUserKey: https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.page.viewstateuserkey
[26] HSTS: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
[27] 此处: https://support.microsoft.com/en-us/help/954002/how-to-add-a-custom-http-response-header-to-a-web-site-that-is-hosted
[28] validateRequest: https://www.asp.net/whitepapers/request-validation
[29] AntiXssEncoder: https://docs.microsoft.com/en-us/dotnet/api/system.web.security.antixss.antixssencoder?view=netframework-4.7.2
[30] Uri.IsWellFormedUriString: https://docs.microsoft.com/en-us/dotnet/api/system.uri.iswellformeduristring
[31] UseDeviceProfile: https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcookiemode?view=netframework-4.7.2
[32] slideExpiration,: https://docs.microsoft.com/en-us/dotnet/api/system.web.security.formsauthentication.slidingexpiration?view=netframework-4.7.2
[33] 则: https://docs.microsoft.com/en-us/dotnet/api/system.web.security.formsauthentication.slidingexpiration?view=netframework-4.7.2
[34] slideExpiration: https://docs.microsoft.com/en-us/dotnet/api/system.web.security.formsauthentication.slidingexpiration?view=netframework-4.7.2
[35] slideExpiration: https://docs.microsoft.com/en-us/dotnet/api/system.web.security.formsauthentication.slidingexpiration?view=netframework-4.7.2
[36] ASP.NET 成员资格提供程序和角色提供程序: https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/membership-and-role-provider
[37] ASP.NET 身份: https://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity
[38] 密码存储备忘单: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
[39] 这里: https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html
[40] 备忘单: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html#net
[41] System.Diagnostics.Process.Start: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.start?view=netframework-4.7.2
[42] 输入验证备忘单: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html
[43] IPAddress.TryParse 方法: https://docs.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=netframework-4.8
[44] LDAP 注入预防速查表上: https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html#introduction
[45] 这里: https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html#introduction
[46] ASP.net Core Identity: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&
[47] 存储加密的密码: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#do-not-limit-the-character-set-and-set-long-max-lengths-for-credentials
[48] 本节: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#guidance
[49] 更多有关静止存储加密密钥的信息: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#guidance
[50] 这里: https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html
[51] LetsEncrypt.org: https://letsencrypt.org/
[52] 允许使用 SSL,现在已过时了: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
[53] SSL 最佳做法: https://www.ssllabs.com/projects/best-practices/index.html
[54] SSL Test: https://www.ssllabs.com/ssltest/
[55] TestSSL: https://testssl.sh/
[56] HttpHeaders.cs: https://github.com/johnstaveley/SecurityEssentials/blob/master/SecurityEssentials/Core/HttpHeaders.cs
[57] Dionach StripHeaders: https://github.com/Dionach/StripHeaders/
[58] startup.cs: https://medium.com/bugbountywriteup/security-headers-1c770105940b
[59] 此处: https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html
[60] 此处: https://owasp.org/www-project-secure-headers/
[61] 此处: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#net
[62] XML 处理选项: https://docs.microsoft.com/en-us/dotnet/standard/data/xml/xml-processing-options
[63] 此处: https://github.com/johnstaveley/SecurityEssentials/blob/master/SecurityEssentials/App_Start/Startup.Auth.cs
[64] 这里: https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html#introduction
[65] 在这里: https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Testing_Automation_Cheat_Sheet.html
[66] 此处: https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html
[67] .NET: https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
[68] .NET Core: https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-3.0#aspnet-core-antiforgery-configuration
[69] 自动生成和验证防伪令牌: https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-3.0#aspnet-core-antiforgery-configuration
[70] tag-helpers: https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro
[71] AutoValidateAntiforgeryToken: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.autovalidateantiforgerytokenattribute?view=aspnetcore-2.2
[72] 文章所述: https://andrewlock.net/automatically-validating-anti-forgery-tokens-in-asp-net-core-with-the-autovalidateantiforgerytokenattribute/
[73] IgnoreAntiforgeryToken: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.ignoreantiforgerytokenattribute?view=aspnetcore-2.2
[74] ValidateAntiforgeryToken: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.validateantiforgerytokenattribute?view=aspnetcore-2.2
[75] AutoValidateAntiforgeryToken: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.autovalidateantiforgerytokenattribute?view=aspnetcore-2.2
[76] 在此处: https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks#anti-csrf-and-ajax
[77] 此处: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
[78] 内容安全策略: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html#context
[79] 此处: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
[80] 备忘单: https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp
[81] 反序列化备忘单: https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp
[82] NuGet: https://docs.microsoft.com/en-us/nuget/
[83] OWASP Dependency Checker,: https://cheatsheetseries.owasp.org/cheatsheets/Vulnerable_Dependency_Management_Cheat_Sheet.html
[84] 备忘单: https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html
[85] 此处: https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger
[86] Application Insights: https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core
[87] 此处: https://github.com/microsoft/code-with-engineering-playbook/tree/master/observability
[88] 在这里: https://github.com/johnstaveley/SecurityEssentials/blob/master/SecurityEssentials/Core/HttpHeaders.cs
[89] HSTS 预载: https://hstspreload.org/
[90] 未经验证的重定向和转发备忘单: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
[91] Security Essentials Baseline 项目。: https://github.com/johnstaveley/SecurityEssentials/
[92] BasicHttpBinding: https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.basichttpbinding?view=netframework-4.7.2
[93] WSHttpBinding: https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.wshttpbinding?view=netframework-4.7.2
[94] TransportWithMessageCredential: https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/ws-transport-with-message-credential
[95] ZAP 之: https://www.zaproxy.org/


来源: owasp.org DotNET 技术圈

原文:https://cheatsheetseries.owasp.org/cheatsheets/DotNet_Security_Cheat_Sheet.html

© 版权声明

☆ END ☆
喜欢就点个赞吧
点赞0 分享
图片正在生成中,请稍后...