八、身份验证、授权和安全

在构建安全的 web 应用时,身份验证、授权和安全性都是需要注意的重要主题。 有很多内容需要讨论,所以我们将关注哪些内容对 ASP 来说是重要的和相关的.NET Core web 应用。

但首先,让我们来定义这三个术语:

  • 认证:你可以使用认证来限制谁可以使用你的应用,而不是允许任何网站访问者访问你的 web 应用。 这对于任何需要在允许与每个用户进行交互之前识别每个用户的应用都很有用。
  • 授权:一旦进入您的应用,您可以使用授权来限制应用的特定部分。 这对于允许某些用户执行其他用户无法访问的一些任务很有用,例如管理任务、数据编辑等等。
  • Security:在这里,Security 是指可能影响 web 应用的安全漏洞。 这包括反请求伪造跨站点脚本,以及SQL 注入

在 ASP 中启用认证功能。 净

你可能会很高兴听到 ASP.NET Core 在其 web 模板中包含了内置的身份验证方法。 事实上,创建前面章节中提到的示例项目将生成一个包含身份验证的 web 应用。 如果您开始一个全新的项目,本节还将帮助您确定需要做什么来包含身份验证。

高层概述

下面是对如何在新的 ASP 中启用身份验证的高级概述.NET Core 应用使用 web 模板:

  1. 用一个网页模板创建一个新项目。
  2. 选择身份验证方法。
  3. 验证包和引用。
  4. 验证Startup.cs类中的代码。
  5. 根据需要添加额外的标识选项。
  6. 根据需要添加外部提供程序。

如果你想从一个空项目开始,你可以执行以下步骤:

  1. 创建一个新的空 web 项目。
  2. 不选择身份验证方法。
  3. 添加用于身份验证的包和引用。
  4. Startup.cs类中添加代码。
  5. 根据需要添加额外的标识选项。
  6. 根据需要添加外部提供程序。

出于显而易见的原因,从一个网页模板开始要容易得多。 注意前面两个列表中的不同之处。 如果你决定从一个空的 web 模板开始,你将不得不做更多的工作来启动和运行认证。

当您选择一个项目类型时,Visual Studio 会在右侧面板中显示一个对话框,其中包含一个标记为Change Authentication的按钮,如下图所示:

High-level overview

如果单击Change Authentication按钮,Visual Studio 将显示另一个对话框,其中显示以下选项:

  • 无身份验证:这是不言自明的。 您的项目不会自动包含任何身份验证,因此应该适用于不需要任何身份验证的 web 应用。 如果您选择稍后添加它,则必须执行额外的步骤来手动添加它。
  • 个人用户帐户:这对于初学者来说非常有用。 所有用户数据都存储在应用数据库中,可以使用 ASP 进行访问.NET Core 框架。 注意:ASP。 asp.net 身份已经从Windows 身份基础转移到 ASP。 净的核心。
  • 工作和学校帐户:该选项包括使用Windows Server Active DirectoryAzure Active Directory的组织帐户,如企业或教育机构帐户。
  • Windows 身份验证:此选项非常适合将在内部网环境中使用的应用,其中 Windows 计算机上的凭据将用于验证 web 应用上的用户。

在本章中,我们将介绍使用个人用户帐户进行身份验证的过程。

认证配置

通过使用前面章节中的医院记录项目,您应该已经有了一个功能良好的 web 项目,并且默认选择了适当的验证方法。 请注意以下验证步骤,以确定在将来的 web 项目中使用空模板时需要什么。

在您的project.json文件中,验证您是否引用了Microsoft.AspNetCore.Identity.EntityFrameworkCore包,如下截图所示:

Authentication configuration

这个 ef 特定的Identity包有两个其他依赖项,您可以在解决方案资源管理器面板中的引用列表中看到这些依赖项。 依赖关系包括以下这些额外的包:

  • Microsoft.AspNetCore.Identity
  • Microsoft.EntityFrameworkCore.Relational

Relational包将Core包作为依赖项拉入EntityFramework,而 ASP.NET 身份包包括我们在项目中需要使用的身份验证。 实体框架将用于与数据库交互,其中我们的用户凭证将存储在一个名为AspNetUsers的表中。

要完成配置,Startup.cs类需要适当的代码来添加和使用身份验证。 正如您可能已经猜到的,这段代码将分别进入ConfigureServices()Configure()方法。

在您的Startup类的ConfigureServices()方法中,验证下面的代码是否能够使用 ASP 的 Identity 特性.NET Core:

services.AddIdentity<ApplicationUser, IdentityRole>() 
    .AddEntityFrameworkStores<ApplicationDbContext>() 
    .AddDefaultTokenProviders(); 

在您的Startup类的Configure()方法中,验证下面的代码是否能够在 ASP 中使用 Identity 特性.NET Core:

app.UseIdentity(); 

有几个配置标志允许我们为使用 Identity 特性定制额外的选项。 这些限制包括但不限于密码限制。 下面的代码展示了这是如何工作的。 例如,如果您想在注册时要求用户的密码中使用数字,您应该将RequireDigit设置为true:

services.AddIdentity<ApplicationUser, IdentityRole>( 
    options => 
    { 
        options.Password.RequireDigit = true; 
        options.Password.RequiredLength = 8; 
        options.Password.RequireLowercase = false; 
        options.Password.RequireNonAlphanumeric= true; 
        options.Password.RequireUppercase = false; 
    }) 
    .AddEntityFrameworkStores<ApplicationDbContext>() 
    .AddDefaultTokenProviders(); 

如果您想研究其他选项,可以在选项列表中的单词选项后输入句号。 这将允许你使用智能感知来发现其他对你有用的东西。 与密码相关的选项在您可能已经在 MVC 模型的密码字段中分配的任何属性之上提供了这些限制。

运行您的应用并单击顶部面板中的Register链接。 注册后,您将作为注册用户自动重定向到应用。 您可以注销,然后使用创建的凭据重新登录。

外部服务提供商

许多用户可能已经拥有希望重用的外部服务提供的帐户。 像 Twitter 和 Facebook 这样的社交媒体巨头提供身份验证服务,你可以很容易地将其集成到你的 ASP 中.NET Core 应用。

困难的部分实际上是在供应商的网站上设置一个应用,一旦你设置了它,就会变得更容易。

以下是建立外部服务提供者所需步骤的概述:

  1. 访问外部提供商的网站,在他们的系统上设置一个应用。
  2. 获取必要的 ID、密钥、秘密或令牌值。
  3. 在您的开发环境中安装Secret Manager工具。
  4. 使用前面获得的值分配秘密值。
  5. 更新您的代码,以便在开发期间使用用户秘密存储。
  6. 更新您的代码以使用第三方提供商,例如 Facebook。
  7. 通过 Facebook 登录到应用来验证身份验证。

在 Azure(云)环境中,您可以在应用设置下为您的 web 应用配置秘密值。我们将在第 9 章部署您的应用中介绍 Azure 部署。

要在外部提供商的系统中设置应用,请访问他们的特定网站:

每个供应商的说明和用户界面可能会随着时间的推移而改变,所以您应该始终访问每个特定的网站以获得最新的说明。 整个过程通常包括创建一个命名的应用,然后获取一组唯一标识你的应用的值。

让我们通过将 Facebook 认证整合到我们的应用中来探索一个特殊的过程:

  1. 请访问https://developers.facebook.com/
  2. 注册为一个新的开发人员。
  3. 创建一个新的应用。
  4. 如果被问到,选择网站平台。
  5. 创建一个带有您选择的显示名称的App Id
  6. 应用创建完成后,进入设置界面。
  7. 记录您的App IdApp Secret值。
  8. 点击添加平台按钮。
  9. 从选择列表中选择网站平台。
  10. 添加你网站的 URL。
  11. Advanced部分,添加您的 URL 作为Redirect URI

在开发过程中测试应用时,可以使用带有适当端口号的本地主机 URL。 要测试一个已部署的网站在一个域名服务器上,你应该使用完全限定域名。 请记住,前面的说明可能会发生变化,所以你应该参考 Facebook 开发者网站上的说明,以防发生变化。

验证如下:

  • 项目的userSecretsId值在您的project.json文件中定义
  • Microsoft.Extensions.Configuration.UserSecrets属于依赖项
  • SecretManager列在project.json文件的工具部分

使用管理权限打开命令提示符。 切换到您的项目目录,然后使用以下 DNU 命令测试 Secret Manager 工具:

>dotnet user-secrets -h

如果您刚刚将SecretManager添加到配置文件中,那么您可能必须在前面的命令之前运行dotnet restore。 验证完SecretManager后,使用以下两个额外命令来存储你从 Facebook 获得的应用 ID 和秘密值:

dotnet user-secrets set Authentication:Facebook:AppId <Value>
dotnet user-secrets set Authentication:Facebook:AppSecret <Value>

注意事项

注意,上面的占位符值必须用实际值替换,命令才能工作。 如果 Facebook 中的值发生了变化,您必须重新运行这两个命令,以确保最新的值存储在开发环境中。

验证你的Startup类中的构造函数中是否有以下一行代码:

builder.AddUserSecrets(); 

这行代码只能在IsDevelopment()返回true时运行,以确保此场景只存在于开发环境中。 为了验证您的环境是否为此正确配置,请确保托管的环境变量被设置为Development,如下面的截图所示。 你可以在你的网页项目的属性面板的Debug选项卡中检查。 你也可以在项目的Properties文件夹下的launchSettings.json文件中看到它:

External service providers

最后,更新Startup.cs中的Configure()方法以使用 Facebook 身份验证。 在调用UseIdentity()之后添加以下代码:

app.UseFacebookAuthentication(new FacebookOptions() 
{ 
    AppId = Configuration["Authentication:Facebook:AppId"], 
    AppSecret = Configuration["Authentication:Facebook:AppSecret"] 
}); 

下次运行应用并尝试登录时,应该会在其他服务列表中看到 Facebook 身份验证选项。 如果你想知道这个 Facebook 按钮是如何显示的,看看代码中Account控制器的Login.cshtml视图,如下截图所示:

External service providers

Login.cshtml视图中(在Views文件夹的Account子文件夹下),有一个由@{}分隔符包围的代码块,用于检查外部身份验证提供程序。 如果找到任何提供程序,将在foreach循环中为每个提供程序显示一个按钮。 该服务器端代码的简化版本如下:

var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList(); 
if (loginProviders.Count == 0) 
{ 
    <p>None configured</p> 
} 
else 
{ 
    <form  
        asp-controller="Account"  
        asp-action="ExternalLogin"  
        asp-route-returnurl="@ViewData["ReturnUrl"]"  
        method="post" class="form-horizontal" role="form"> 

    @foreach (var provider in loginProviders) 
    { 
        <button  
            type="submit"  
            class="btn btn-default"  
            name="provider"  
            value="@provider.AuthenticationScheme"  
            > 
        @provider.AuthenticationScheme 
        </button> 
    } 
    </form> 
} 

登录后,您的身份验证应该由 Facebook 处理,您可能会被提示登录 Facebook。 如果您已经在当前窗口登录到 Facebook,您当前的会话将被使用。 在这两种情况下,您都应该被重定向回您的应用,并且您的用户名将是您可能用于登录 Facebook 的登录名(例如,您的电子邮件地址)。

默认情况下,你的 Facebook 帐户将是 Facebook 应用的管理员。当你登录到你的 web 应用时,你将被要求将你的 Facebook 帐户与 web 应用的用户系统中的一个新帐户相关联。 您可以通过在关联屏幕中输入新的电子邮件地址来注册一个新帐户。 如果你想在测试期间添加额外的用户,你必须首先进入 Facebook 开发者网站上的角色标签页,在那里你可以添加额外的管理员、开发人员和测试人员。

为应用特性使用授权

正如在本章的介绍中所解释的,授权可以用于将已经通过身份验证的用户排除在应用的特定部分之外。 在我们的医院记录应用中,我们可以限制某些功能,以便医生可以访问它们,而护士或患者则不能。

高层概述

下面是对如何在 ASP 中实现基本授权技术的高级概述.NET Core 应用:

  1. 在控制器代码中使用Authorization命名空间。
  2. 在控制器类级别授予授权。
  3. 在控制器操作方法级别授予授权。
  4. 在控制器类级别授予匿名访问。
  5. 在控制器操作方法级别授予匿名访问。

尽管第一步是使用授权所必需的,但其余建议不必按照任何特定的顺序执行。 实际上,您可以对一个控制器类或一个方法进行授权,或者两者都授权,或者根本不授权。 在所有情况下,如果您授予匿名访问,它将优先于任何其他授权。 例如,同时具有授权和匿名访问集的类将向任何用户授予匿名访问权。

实现授权的最简单方法是使用基于角色的授权基于声明的授权。 我们将在本节中介绍这两种技术。 有关更复杂的授权技术的更完整列表,请参阅以下网址的官方文档:

http://docs.asp.net/en/latest/security/authorization

基本授权

要配置授权,最快的方法是简单地将Authorize属性添加到特定的控制器类。 下面的代码展示了如何将其应用到HumanController:

[Authorize] 
public class HumanController : Controller 
{ 
} 

为了使用Authorize属性,请确保在类定义上面有正确的 using 语句:

using Microsoft.AspNetCore.Authorization; 

从 Visual Studio 运行应用,并单击顶部工具栏中的Humans链接来访问HumanController。 由于控制器在类级别上受到了限制,如果您尝试在不首先登录的情况下访问HumanController,那么您将被重定向到Login页面。

要尝试匿名访问,将[AllowAnonymous]属性添加到HumanController类的Index()操作方法:

[AllowAnonymous] 
public async Task<IActionResult> Index() 

再次运行应用,然后再次单击Humans链接。 即使控制器已经在类级别限制,Index()的方法会让你访问Index视图,而无需登录,但试图访问【编辑 T7】/【显示】删除将提示您登录的链接。 即使在操作方法上有[Authorize]属性和[AllowAnonymous]属性时,这种覆盖行为也会工作。

角色与主张

除了基本的身份验证之外,我们还可以实现基于角色的授权和基于声明的授权,以实现更精确的访问控制。 这些类型的授权依赖于以下 ASP。 网相关的表:

  • AspNetUsers:带有用户 ID、电子邮件、密码等的用户表
  • AspNetRoles:角色主列表
  • AspNetUserRoles:映射到特定角色的用户
  • AspNetUserClaims:映射到特定索赔的用户
  • AspNetRoleClaims:映射到特定索赔的角色(以及用户)

要用一些示例数据填充数据库,请执行以下步骤创建新用户、角色和声明。 为了测试而使用假的电子邮件地址是可以的。 要与数据库交互,可以使用 Visual Studio 中的SQL Server 对象资源管理器面板来扩展患者记录数据库的内容。

您可以右键单击任何表,选择View Data查看(并编辑)其数据:

  1. 从 Visual Studio 中运行应用。
  2. 在浏览器中,单击右上方菜单中的Register
  3. 在浏览器中注册几个用户(例如,医生、护士、病人)。
  4. 在数据库中,验证AspNetUsers表中的用户。
  5. AspNetRoles表中添加几个角色,并使用顺序的 ID 值。
  6. AspNetUserRoles表中添加一些记录,将用户映射到角色。
  7. AspNetUserClaims表添加一些记录,将用户映射到索赔。
  8. 暂时将AspNetRoleClaims表空着。

如果您需要帮助将数据添加到AspNetRoles表中,以下是一些示例值:

| Id | concurrent stamp | 名称 | NormalizedName | | 1 | 零 | 管理员 | 管理员 | | 2 | 零 | 医生 | 医生 | | 3 | 零 | 护士 | 护士 |

如果您需要帮助将数据添加到AspNetUserRoles表中,以下是一些示例值:

| 用户名 | 角色 | | cb09fda1-1458-4da1-bee8-3e831d68ca8c | 3 | | e8104b13-72e6-497f-baac-0619548c1e70 | 2 |

不应该将前面的UserId值复制到AspNetUserRoles中。 相反,您应该检查自己的AspNetUsers表来复制分配给每个用户UserId字段的global Unique ID(GUID)值。 这些是由内置的注册工具自动生成的。 下面是AspNetUsers表的一个示例:

| 用户名 | Email | | | cb09fda1-1458-4da1-bee8-3e831d68ca8c | RobotNurse1@fakedomain.com | | | e8104b13-72e6-497f-baac-0619548c1e70 | RobotDoctor1@fakedomain.com | |

最后,如果您需要帮助将数据添加到AspNetUserClaims表中,下面是一些示例值。 在该表中,ID 值是按顺序自动生成的:

| Id | | ClaimValue | 用户名 | | 1 | DoctorCred | 123456789 | e8104b13-72e6-497f-baac-0619548c1e70 | | 2 | NurseCred | 987654321 | cb09fda1-1458-4da1-bee8-3e831d68ca8c |

现在你的数据已经全部设置好了,用如下所示的属性装饰你的动作方法:

[Authorize(Roles = "Doctors,Nurses")] 
public async Task<IActionResult> Index() 

[Authorize(Roles = "Doctors")] 
public IActionResult Create 

上述代码确保以下情况:

  • 医生和护士都可以进入主要的Index视图
  • 只有医生能够创建一个新的条目

本文将介绍基于角色的授权的设置和使用。 要使用基于 claims 的 Authorization,您必须更新启动配置,并在控制器代码中使用其他属性和参数。

Startup.cs文件的ConfigureServices()方法中,在AddMvc()调用之后添加一个对AddAuthorization()的调用,如下所示:

services.AddAuthorization(options => 
{ 
    options.AddPolicy("DoctorsOnly",  
        policy => policy.RequireClaim("DoctorCred")); 

}); 

这将向您的应用添加一个名为DoctorsOnly的新保单,并要求索赔DoctorCred。 您可能还记得,DoctorCred就是我们在本节前面添加到AspNetUserClaims表中的ClaimType。 要使用这个声明,只需向Details()方法添加以下属性,如下所示:

[Authorize(Policy = "DoctorsOnly")] 
public async Task<IActionResult> Details(int? id) 

这确保了只有具有DoctorCred声明的用户才能访问人类患者列表的详细信息。 为了更进一步,重新定义索赔以包含特定的索赔编号。 这个值可以是一个或多个逗号分隔值的集合:

services.AddAuthorization(options => 
{ 
    options.AddPolicy("DoctorsOnly",  
        policy => policy.RequireClaim("DoctorCred", "123456789")); 

}); 

运行应用并以前面创建的各种用户身份登录。 验证您正在观察基于每个用户的授权特权所期望的行为。 如果没有适当的权限,您可能会看到一个Access Denied错误页面。

保护您的数据

ASP.NET Core 包含了一个新的数据保护系统,可以在 web 应用和控制台应用中使用。 你可能还记得 ASP 的模板列表.NET Core 包含一个控制台应用,在前面的章节中我们不需要使用它,如下截图所示。 然而,这种项目类型对于说明框架特性是一个很好的选择,例如在 ASP 中使用数据保护.NET Core:

Protecting your data

元素在以前的 ASP 版本中使用了<machinekey>。 而新的数据保护堆栈将取代它。 为了使事情更简单,新系统鼓励以最小的配置工作来使用它。 同时,还有一些可扩展性 api 允许根据需要进行更多定制。

ASP 中的数据保护.NET Core

当用户与 web 应用通信时,有许多方法来持久化和传输数据。 有些方法比其他方法更持久,而安全性和加密可能差异很大。 提供给经过身份验证的用户的令牌在以后使用时需要受到信任。 这就是数据保护的作用所在。

ASP.NET 团队在构建新的数据保护系统时确定了一些要求:真实性、机密性和隔离性。 通过确保我们可以担保受保护数据的完整性,同时保护数据不受不可信客户的影响,可以满足所有这些要求。 请注意,这并不能防止恶意应用滥用 API 来访问不应该访问的受保护数据。

实施数据保护

使用新的Data Protection API设置项目是相当简单的。 这是有意为之,并允许开发人员快速启动和运行。 请记住,受保护的数据不应该是您希望无限期存储的数据。 这在技术上是可行的,但不推荐使用。

要开始,使用以下步骤创建一个新的控制台应用:

  1. 在 Visual Studio 2015 中点击File|New|Project
  2. Installed模板列表中,选择Visual c#|. net Core|Console Application(控制台应用).NET Core)
  3. 输入DataProtectionApp作为项目名称,然后单击OK
  4. 打开project.json文件进行编辑。
  5. 将以下引用添加到依赖列表中:
      "Microsoft.AspNetCore.DataProtection":"1.0.0", 
      "Microsoft.Extensions.DependencyInjection": "1.0.0" 

当您输入版本号时,您很可能会使用可用的最稳定的版本。 在DataProtection名称空间中,您可以访问数据保护提供者及其保护和取消数据保护的方法。 命名空间将允许您使用 DI 轻松地设置数据保护。 你要用一根所谓的用途线把它们绑在一起。

编辑Program.cs文件的Main()方法,包含以下代码:

var serviceCollection = new ServiceCollection(); 
serviceCollection.AddDataProtection(); 
var services = serviceCollection.BuildServiceProvider(); 

var instance = ActivatorUtilities.CreateInstance<DataProtector>(services); 
instance.ProtectAndRelease(); 

要使用ServiceCollectionActivatorUtilities类,请确保将下面的 using 语句添加到Program类的顶部。

using Microsoft.Extensions.DependencyInjection;  

前面的代码创建了我们接下来将创建的DataProtector类的实例。 它将有一个公共的ProtectAndRelease()方法。 您可能已经猜到了,该方法将负责保护一些输入数据,然后将其作为未保护数据发布。 在实际场景中,您可能不会使用相同的方法取消对数据的保护。

要创建DataProtector类,请遵循以下步骤:

  1. 在“解决方案资源管理器”面板中右键单击项目。
  2. 从弹出的菜单中选择添加|Class
  3. 命名类DataProtector.cs,点击添加,如下图所示:

Implementing data protection

DataProtector类中添加以下实例变量和构造函数:

IDataProtector _protector;         
public DataProtector(IDataProtectionProvider provider) 
{ 
    _protector = provider.CreateProtector("Company.Project.v1"); 
} 

为了使用IDataProtectorIDataProtectionProvider接口,请确保在DataProtector类的顶部添加以下命名空间:

using Microsoft.AspNetCore.DataProtection; 

构造函数负责创建新的数据保护提供程序对象,该对象又用于创建新的保护程序。 Company.Project.v1目的字符串用于创建用于此示例的保护器。 这个字符串可以是您想要的任何内容,但建议您对您的应用使其独一无二。 在同一个应用的其他地方,创建一个具有相同目的字符串的保护程序将允许该保护程序取消对先前被第一个保护程序保护的数据的保护。

最后,添加以下方法来保护和取消对数据的保护。 方法可以采用字符串值或字节数组作为输入参数:

public void ProtectAndRelease() 
{ 
    Console.Write("Enter input: "); 
    string userToken = Console.ReadLine(); 

    string protectedToken = _protector.Protect(userToken); 
    Console.WriteLine($"Protected token: {protectedToken}"); 

    string unprotectedToken = _protector.Unprotect(protectedToken); 
    Console.WriteLine($"Unprotected result: {unprotectedToken}"); 

    Console.ReadKey(); 
} 

现在可以运行应用了。 从 Visual Studio 中运行应用并输入一些示例文本,例如文本字符串形式的用户标记。 您应该立即看到来自ProtectAndRelease()方法的输出,它显示了您输入的文本的受保护版本和未受保护版本:

Implementing data protection

您可能想要将这些数据保护代码添加到您的 ASP.NET Core 控制器在您的 web 项目。 相反,您应该考虑抽象服务类来处理应用的特定部分,以保持控制器的精简。

这一切是如何运作的

为了理解所有这些是如何工作的,让我们回到目的字符串。 它的用途可以是字符串、字符串列表,甚至是方法调用的菊花链。 你可以使用这里显示的任何一种格式:

CreateProtector("Company.Project.v1"); 
CreateProtector(new List<string> { "Comp", "Proj", "v1" }); 
CreateProtector("Comp.Proj").CreateProtector("v1"); 

只要两个提供程序对象被认为是等效的,一个提供程序就可以取消被另一个提供程序保护的数据的保护。 记住以下几点:

  • 如果目的字符串以相同的顺序包含相同的字符串,则认为它们是等效的
  • 如果提供程序对象是用等效的字符串值创建的,则认为它们是等效的
  • 如果保护者对象是由等效的提供者对象创建的,则认为它们是等效的
  • 在内部,系统在目的链中使用一个对应用唯一的标识符

以下是一些你应该注意的注意事项:

  • 如果在构建目的字符串时使用了任何用户输入,则向该字符串追加一些内容,以防止用户控制目的字符串的整体外观。
  • 你应该在它发生的地方抓住一个CryptographicException。 如果使用不同的数据保护程序来尝试取消保护操作,或者负载被篡改,则会抛出此类异常。
  • 这种数据保护方法不能保护恶意应用代码本身。 如果相同的目的字符串在不应该重用的地方被重用,这可能会导致在您不需要它们的地方产生等效的提供者对象。

这并不是您需要了解的关于 ASP 中数据保护的全部内容。 净的核心。 欲了解更多信息,请浏览以下网址获取官方文件:

https://docs.asp.net/en/latest/security/data-protection

实现 web 应用安全

在网络向世界普及后不久,网络应用开始到处涌现。 伴随着 web 应用而来的漏洞可能会被恶意用户利用。 幸运的是,安全专家和框架开发人员不断提供持续的建议和更好的安全措施。

多年来,一些常见的安全漏洞包括:

  • SQL 注入:SQL 通过 HTML 表单字段注入恶意 SQL 脚本,这些字段的值用于构建 SQL 的文本字符串。 通过使用LINQ对具有 ORM(如 EF Core)的实体,可以避免 SQL 注入的风险。 如果您发现自己正在使用参数化查询,请确保在查询参数中使用任何用户输入(通过 html 编码值)之前对它们进行消毒。
  • 敏感数据暴露:关于服务器、文件系统、数据库和操作系统的信息可能在生产环境中不必要地暴露出来,特别是在出现错误的情况下。 最好避免向最终用户透露过多的信息。 相反,如果发生错误,可以利用内置的日志功能将详细信息存储在其他地方,同时向用户显示数字错误代码和友好的消息。
  • 跨站脚本(XSS):恶意脚本代码通常通过QueryString参数注入到 HTML 页面的主体中。 幸运的是,有多种方法来抵御 XSS 攻击。

本节的其余部分将探讨一些技术,用于对抗 XSS、防止伪造和支持跨源请求。

跨站点脚本

为了防止来自恶意用户的跨站点脚本攻击,您可以将AntiXSS库与以前的 ASP.NET 版本一起使用。 然而,AntiXSS 在 2015 年底就已经被认为使用寿命结束了。 因此,AntiXSS 库不兼容。net Core 1.0。

来自 AntiXSS 库最新版本的Sanitizer对象包含一个方法,可以将可能不安全的 HTML 代码转换为更安全的替代代码。 作为替换,你可以让剃刀引擎在 ASP.NET MVC 自动编码来自不可信源的变量值。 最终的目标是确保应用的用户不会将恶意客户端脚本注入到 HTML 主体中。

更多关于 ASP 中 HTML 编码的详细信息.NET MVC web 应用,查看 asp.net 的 XSS 部分的 HTML 编码部分。 网络文档:

https://docs.asp.net/en/latest/security/cross-site-scripting.html

防伪

[ValidateAntiForgeryToken]属性为您的 web 应用提供了内置的防伪支持。 它生成一个只包含 http 的 cookie,该 cookie 的值也写入 HTML 表单。 如果在 HTTPPOST操作发生后,值不匹配,这将发出一个红色信号,表明可能发生了跨站点请求伪造(CSRF); 也就是说,提交的表单与服务器最初提供的表单不同。

你可能已经注意到这个[ValidateAntiForgeryToken]属性已经被应用到 web 项目模板提供的AccountController中的几个动作方法:

[HttpPost] 
[ValidateAntiForgeryToken] 
public async Task<IActionResult> MethodName(...) 
{ 
        // ... 
} 

如果你需要为特定的表单禁用这个特性,你可以在你想要的视图中将标签帮助器asp-anti-forgery属性设置为 false:

<form asp-controller="controllerName"  
      asp-antiforgery="false"asp-anti-forgery="false" 
      asp-action="methodName"> 
</form> 

跨源请求

由于所谓的同源策略,web 浏览器通常会阻止 web 页面向不同域的页面发出 AJAX 请求。 然而,您的 web 应用可能需要接受来自不同域的 AJAX 请求。 幸运的是,万维网联盟(W3C)组织定义了一个名为跨源资源共享(CORS)的标准,该标准支持跨源请求。

要判断两个 URL 是否同源,需要比较每个 URL 的域名、子域名、端口号和方案(HTTP/HTTPS)。 如果它们是不同的,那么 CORS 就是一个有用的工具。 在 ASP 中启用 CORS.NET Core,遵循这里列出的简单步骤:

  1. 在您的project.json文件中添加对 CORS 包的引用。
  2. 更新ConfigureServices()方法添加Cors
  3. Configure()方法更新为Cors
  4. 在控制器代码中使用属性自定义 CORS 行为。

要添加对项目的引用,请在project.json文件的依赖项部分添加以下包:

"Microsoft.AspNetCore.Cors": "1.0.0" 

要设置您的配置,请将以下代码添加到Startup类的ConfigureServices()方法中的AddCors()中。 您可以将其直接添加到AddMvc():

services.AddCors(options => 
{ 
    options.AddPolicy("AllowSpecificOrigin", 
        builder => 
        { 
            builder.WithOrigins("http://fakedomain.com"); 
        }); 
}); 

前面的代码将 CORS 功能添加到应用中,同时显式地指定了命名的AllowSpecificOrigin策略。 它允许来自 fakedomain.com 的跨源请求通过您的网站进行处理。

要在控制器类级别启用 CORS,请使用[EnableCors]属性:

[EnableCors("AllowSpecificOrigin")] 
public class MyController: Controller 

要在控制器方法级别启用 CORS,使用相同的属性:

[EnableCors("AllowSpecificOrigin")] 
public IActionResult ActionMethod() 

在这两种情况下,添加正确的 using 语句来包含 CORS 命名空间:

using Microsoft.AspNetCore.Cors; 

方法级别的设置优先于控制器级别的设置,控制器级别的设置优先于应用级别的设置。 这允许我们在选择的任何级别禁用 CORS,即使它已经在应用级别启用。 例如,如果只需要为特定的方法禁用 CORS,则可以将[DisableCors]属性添加到特定的方法。

要在全局级别上在应用中添加AllowSpecificOrigin策略,请将以下代码添加到ConfigureServices()方法中。 您可以在调用AddMvc()之后添加以下代码:

services.Configure<MvcOptions>(options => 
{ 
    options.Filters.Add( 
        new CorsAuthorizationFilterFactory("AllowSpecificOrigin")); 
}); 

为了在您的Startup类中使用MvcOptionsCorsAuthorizationFilterFactory类,您必须在类的顶部添加以下名称空间:

using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Mvc.Cors.Internal; 

总结

在本章中,我们讨论了提供访问应用的一些方法以及限制访问它的其他方法。 您可以使用身份验证来验证用户的身份,同时也可以使用授权来支持访问应用的特定部分。 您可以使用新的数据保护系统保护少量数据,同时您可以采取几个不同的操作来保护您的应用免受众所周知的安全风险。

在下一章和最后一章中,我们将介绍部署过程。 如果 web 应用只存在于您的开发环境中,那么它就不是一个好的应用。 通过将应用部署到公共网站,您可以接触到全球用户。 通过部署到云,您可以扩展您的网站以满足公众需求。