云环境下ASP.NET Core Web应用的安全认证方案
1. 云环境与传统部署的差异
在云环境中,无论是公共云还是本地PaaS平台,其运行方式与传统的物理或虚拟机Windows部署有很大不同。云环境下支撑应用的操作系统具有临时性,可能会定期或随机被销毁,因此不能期望其加入某个域,很多情况下,支持云应用的操作系统会被频繁且有意地销毁,比如一些公司在滚动更新时会销毁并重建所有虚拟机,以减少持续攻击的潜在风险。
2. 传统认证方式的局限性
由于代码采用跨平台的.NET Core,无法依赖仅适用于Windows应用的功能,因此集成Windows身份验证不可行,需要为云服务寻找其他替代方案。
3. 表单认证与Cookie认证
- 表单认证原理 :有过传统ASP.NET Web应用开发经验的人对表单认证应该很熟悉。在这种认证模式下,应用会展示一个自定义的用户界面(表单),提示用户输入凭证,凭证会直接传输到应用并由应用进行验证。用户成功登录后,会收到一个用于标记其在一段时间内已认证的Cookie。
- PaaS平台下的负担 :在PaaS平台上运行应用时,表单认证本身并没有本质的好坏之分,但会给应用带来一些额外负担。表单认证要求应用维护和验证凭证,这意味着需要处理机密信息的安全、加密和存储。不过,还有其他选择可以将身份的维护和验证工作交给第三方,让应用专注于核心业务价值。
4. 云应用的加密问题
- 传统加密方式的困境 :在传统ASP.NET应用中,加密常用于创建安全的身份验证和会话Cookie,这种加密方式会使用机器密钥来加密和解密Cookie。但对于云原生服务开发者来说,“机器密钥”是一个令人担忧的问题,因为在云环境中不能依赖特定的机器或这些机器上的特定文件,应用可能在任何容器、任何虚拟机上启动,无法保证单一加密密钥能在应用运行的每台机器上都可用。
- 解决方案 :将加密密钥的存储和维护作为一种后端服务,即该服务独立于应用,就像状态、文件系统、数据库和其他微服务一样。
5. 承载令牌(Bearer Tokens)
- 令牌的作用与传输 :如果应用不是用户身份和授权的中央权威,就需要能够接受身份和授权证明。常见的以HTTP友好且便携的方式传输身份证明的方法是使用承载令牌。理想情况下,应用通过Authorization头接受承载令牌,例如:
POST /api/service HTTP/1.1
Host: world-domination.io
Authorization: Bearer ABC123HIJABC123HIJABC123HIJ
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) etc...etc...etc...
- 令牌的验证流程 :在正常的服务流程中,服务会从Authorization头中提取令牌。许多令牌格式(如OAuth 2.0的JWT)通常以Base64、URL友好的格式编码,验证这些令牌的第一步是将其解码以获取原始内容。如果令牌是用私钥加密的,服务会使用公钥来验证令牌是否由适当的权威机构颁发。
6. OpenID Connect(OIDC)基础
- OIDC概述 :OIDC是OAuth2标准的超集,包含了身份提供者(IDP)、用户和应用之间安全通信的规范和标准。根据应用类型和安全要求,可以选择多种认证流程。
- 简单OIDC流程 :
graph LR
A[未认证用户] -->|请求受保护资源| B[网站]
B -->|重定向| C[身份提供者]
C -->|返回代码| B
B -->|POST请求包含客户端ID、客户端密钥和代码| C
C -->|返回OIDC令牌(JWT格式)| B
B -->|写入认证Cookie并跳转| D[主页或原受保护资源]
在这个流程中,未认证用户请求网站上的受保护资源,网站将用户重定向到身份提供者,身份提供者在认证后返回一个短有效期的代码,网站再向身份提供者发送包含客户端ID、客户端密钥和代码的POST请求,获取OIDC令牌。网站验证令牌后,写入认证Cookie并将用户重定向到主页或原受保护资源。这种简单流程较为安全,因为承载声明的令牌不会暴露在URL上,只会以短寿命的字符串形式通过安全连接交换为令牌。
7. 使用OIDC保护ASP.NET Core应用
-
准备工作
:
- 创建空Web应用 :在终端使用以下命令创建一个基于MVC的启动Web应用:
$ dotnet new mvc
- **设置身份提供者**:可以选择多种身份提供者,如企业环境中的Active Directory Federation Services(ADFS)、Azure AD等。为了提供一个无需大量基础设施投资和前期成本的示例,选择Auth0作为身份提供者。具体步骤如下:
1. 访问http://auth0.com ,注册并登录到仪表板。
2. 点击“Create Client”按钮,选择“Regular Web Application”作为应用类型。如果选择ASP.NET Core作为实现语言,会看到一个快速入门教程,其代码与示例代码相似。
3. 按照Auth0 .NET Core教程开头的所有说明进行配置,将高级设置中的OAuth JWT签名算法改为RS256。可以根据需要选择连接到私有用户数据库或接受其他常见的OIDC身份,如Facebook和Twitter。
- **使用OIDC中间件**:无需编写实现OIDC标准重定向和其他底层细节的所有代码,只需决定何时发起挑战(强制用户向IDP进行身份验证)并配置OIDC中间件。以下是修改后的`Startup.cs`文件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Http;
namespace StatlerWaldorfCorp.SecureWebApp
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json",
optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(
options => options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme);
// Add framework services.
services.AddMvc();
services.AddOptions();
services.Configure<OpenIDSettings>(
Configuration.GetSection("OpenID"));
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IOptions<OpenIDSettings> openIdSettings)
{
Console.WriteLine("Using OpenID Auth domain of : " +
openIdSettings.Value.Domain);
loggerFactory.AddConsole(
Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
var options =
CreateOpenIdConnectOptions(openIdSettings);
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("name");
options.Scope.Add("email");
options.Scope.Add("picture");
app.UseOpenIdConnectAuthentication(options);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
private OpenIdConnectOptions CreateOpenIdConnectOptions(
IOptions<OpenIDSettings> openIdSettings)
{
return new OpenIdConnectOptions("Auth0")
{
Authority =
$"https://{openIdSettings.Value.Domain}",
ClientId = openIdSettings.Value.ClientId,
ClientSecret = openIdSettings.Value.ClientSecret,
AutomaticAuthenticate = false,
AutomaticChallenge = false,
ResponseType = "code",
CallbackPath = new PathString("/signin-auth0"),
ClaimsIssuer = "Auth0",
SaveTokens = true,
Events = CreateOpenIdConnectEvents()
};
}
private OpenIdConnectEvents CreateOpenIdConnectEvents()
{
return new OpenIdConnectEvents()
{
OnTicketReceived = context =>
{
var identity =
context.Principal.Identity as ClaimsIdentity;
if (identity != null) {
if (!context.Principal.HasClaim(
c => c.Type == ClaimTypes.Name) &&
identity.HasClaim( c => c.Type == "name"))
identity.AddClaim(
new Claim(ClaimTypes.Name,
identity.FindFirst("name").Value));
}
return Task.FromResult(0);
}
};
}
}
}
在上述代码中,通过配置系统读取
OpenIDSettings
类的选项作为服务,该类包含OIDC客户端所需的四个元数据:授权域(IDP的根主机名)、客户端ID(由IDP颁发)、客户端密钥和回调URL(告知IDP认证后如何将用户重定向回网站)。同时,代码中还设置了Cookie认证和OpenID Connect认证,并在
CreateOpenIdConnectEvents
方法中处理认证票据返回后的声明转换。
8. 账户控制器的实现
为了实现登录、注销和显示用户声明等功能,添加了一个账户控制器
AccountController
:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Authorization;
using System.Linq;
using System.Security.Claims;
namespace StatlerWaldorfCorp.SecureWebApp.Controllers
{
public class AccountController : Controller
{
public IActionResult Login(string returnUrl = "/")
{
return new ChallengeResult("Auth0",
new AuthenticationProperties() {
RedirectUri = returnUrl
});
}
[Authorize]
public IActionResult Logout()
{
HttpContext.Authentication.SignOutAsync("Auth0");
HttpContext.Authentication.SignOutAsync(
CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToAction("Index", "Home");
}
[Authorize]
public IActionResult Claims()
{
ViewData["Title"] = "Claims";
var identity =
HttpContext.User.Identity as ClaimsIdentity;
ViewData["picture"] =
identity.FindFirst("picture").Value;
return View();
}
}
}
-
登录功能
:
Login方法会发起一个挑战,将用户重定向到身份提供者进行认证。 -
注销功能
:
Logout方法会同时注销“Auth0”和Cookie认证方案,确保用户的登录信息被清除。 -
声明显示功能
:
Claims方法会搜索用户身份中的“picture”声明,并将其值放入ViewData字典中。
9. 声明视图的实现
以下是用于显示用户声明的
Claims.cshtml
视图代码:
<div class="row">
<div class="col-md-12">
<h3>Current User Claims</h3>
<br/>
<img src="@ViewData["picture"]" height="64" width="64"/><br/>
<table class="table">
<thead>
<tr>
<th>Claim</th><th>Value</th>
</tr>
</thead>
<tbody>
@foreach (var claim in User.Claims)
{
<tr>
<td>@claim.Type</td>
<td>@claim.Value</td>
</tr>
}
</tbody>
</table>
</div>
</div>
该视图会遍历用户的声明集合,并以表格形式显示声明类型和值,同时显示用户的图片。
10. 注意事项
不同的身份提供者对声明的支持可能不同,并非所有IDP都会提供“picture”声明,在编写依赖特定声明的代码之前,一定要确保从IDP获取到所有保证可用的声明列表。
通过以上步骤和代码示例,可以在云环境下使用OIDC和承载令牌为ASP.NET Core Web应用提供安全的身份验证和授权机制。
云环境下ASP.NET Core Web应用的安全认证方案
11. 配置文件细节
在前面提到了
OpenIDSettings
类所需的元数据,这些信息通常存储在
appsettings.json
文件中,示例如下:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"OpenID": {
"Domain" : "bestbookeverwritten.auth0.com",
"ClientId" : "<client id>",
"ClientSecret": "<client secret>",
"CallbackUrl": "http://localhost:5000/signin-auth0"
}
}
这个配置文件包含了日志记录的相关设置以及OIDC所需的关键信息。由于这些信息比较敏感,在实际开发中通常不会将
appsettings.json
文件提交到版本控制系统。
12. 认证中间件的作用分析
在
Startup.cs
文件中,使用了多个认证中间件,下面详细分析它们的作用:
| 中间件 | 作用 |
| ---- | ---- |
|
app.UseCookieAuthentication
| 启用Cookie认证,设置
AutomaticAuthenticate
为
true
表示自动对请求进行认证,
AutomaticChallenge
为
true
表示在用户未认证时自动发起挑战。 |
|
app.UseOpenIdConnectAuthentication
| 启用OpenID Connect认证,通过
CreateOpenIdConnectOptions
方法配置认证选项,包括认证机构、客户端ID、客户端密钥等信息。 |
这些中间件协同工作,确保应用能够正确处理用户的认证请求。
13. 代码中的声明转换逻辑
在
CreateOpenIdConnectEvents
方法中,有一段声明转换的逻辑:
private OpenIdConnectEvents CreateOpenIdConnectEvents()
{
return new OpenIdConnectEvents()
{
OnTicketReceived = context =>
{
var identity =
context.Principal.Identity as ClaimsIdentity;
if (identity != null) {
if (!context.Principal.HasClaim(
c => c.Type == ClaimTypes.Name) &&
identity.HasClaim( c => c.Type == "name"))
identity.AddClaim(
new Claim(ClaimTypes.Name,
identity.FindFirst("name").Value));
}
return Task.FromResult(0);
}
};
}
这段代码的作用是将OIDC令牌中的
name
声明转换为ASP.NET Core身份系统所使用的
ClaimTypes.Name
声明。因为ASP.NET Core的身份系统依赖于
ClaimTypes.Name
来确定用户的名称,而OIDC JWT令牌中的用户名称声明为
name
,所以需要进行这样的转换,否则用户的名称可能会显示为
null
。
14. 多认证方案的处理
在
AccountController
的
Logout
方法中,处理了多认证方案的注销操作:
[Authorize]
public IActionResult Logout()
{
HttpContext.Authentication.SignOutAsync("Auth0");
HttpContext.Authentication.SignOutAsync(
CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToAction("Index", "Home");
}
ASP.NET Core支持同时使用多种认证方案,在这个示例中,同时使用了Cookie认证和名为“Auth0”的认证方案。当用户注销时,需要确保两种认证方案的登录信息都被清除,以保证用户完全退出应用。
15. 不同类型应用的OIDC认证流程对比
不同类型的应用,如单页Web应用、移动应用和传统Web应用,可能会使用不同的OIDC认证流程。下面通过表格对比简单OIDC流程和其他可能的复杂流程:
| 应用类型 | 认证流程特点 |
| ---- | ---- |
| 传统Web应用(简单OIDC流程) | 用户请求受保护资源,重定向到身份提供者,获取代码后交换令牌,写入认证Cookie并跳转。承载声明的令牌不暴露在URL上,安全性较高。 |
| 复杂流程应用 | 可能涉及资源概念和更复杂的重定向循环,获取访问令牌的过程更繁琐,但能满足更复杂的安全和业务需求。 |
16. 安全认证的最佳实践总结
为了在云环境下更好地实现ASP.NET Core Web应用的安全认证,以下是一些最佳实践:
-
选择合适的身份提供者
:根据应用的需求和场景,选择可靠且功能丰富的身份提供者,如Auth0等,同时要考虑其对不同认证流程和声明的支持。
-
妥善管理敏感信息
:像客户端ID、客户端密钥等敏感信息要妥善存储和管理,避免泄露。可以使用环境变量或配置管理工具来保护这些信息。
-
遵循安全标准
:使用OIDC等成熟的安全标准,确保身份验证和授权过程的安全性和规范性。
-
测试和验证
:在开发和部署过程中,对认证流程进行充分的测试和验证,确保不同场景下的认证功能正常工作。
17. 未来安全认证的发展趋势
随着云计算和Web应用的不断发展,安全认证领域也在不断演进。未来可能会出现以下趋势:
graph LR
A[多因素认证普及] --> B[增强安全性]
C[零信任架构应用] --> B
D[生物识别技术融合] --> B
B --> E[更安全的云应用环境]
- 多因素认证普及 :除了传统的用户名和密码认证,会更多地结合短信验证码、指纹识别、面部识别等多因素进行认证,提高安全性。
- 零信任架构应用 :不再默认信任内部或外部的任何网络和设备,对任何访问请求都进行严格的身份验证和授权,确保数据和应用的安全。
- 生物识别技术融合 :将生物识别技术如指纹、面部识别等与OIDC等认证标准相结合,提供更便捷和安全的认证方式。
通过关注这些趋势,可以提前做好准备,为ASP.NET Core Web应用的安全认证提供更强大的保障。
综上所述,在云环境下为ASP.NET Core Web应用实现安全认证需要综合考虑多种因素,选择合适的认证方案和身份提供者,遵循安全标准,并不断关注安全认证领域的发展趋势,以确保应用的安全性和可靠性。
超级会员免费看
3318

被折叠的 条评论
为什么被折叠?



