15、云环境下ASP.NET Core Web应用的安全认证方案

云环境下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应用实现安全认证需要综合考虑多种因素,选择合适的认证方案和身份提供者,遵循安全标准,并不断关注安全认证领域的发展趋势,以确保应用的安全性和可靠性。

为了查找与测绘遥感相关的SCI期刊列表,可以通过学术搜索引擎或访问特定的数据库来获得最新的信息。通常这些资源会定期更新以反映最新收录情况。 些常用的搜索方式包括: 查阅Web of Science (WOS) 数据库 这是最直接的方法之,因为Science Citation Index(SCI)正是由该数据库维护。可以在其中设置关键词为"remote sensing", "surveying and mapping" 或者更具体的主题术语,并选择仅显示被SCI索引的文章和期刊。 利用Google Scholar 虽然不是专门针对SCI期刊,但可以找到很多高影响力的测绘遥感类文章及其发表刊物的信息。从这里也可以了解到哪些是活跃且受认可的研究领域内的出版物。 参考Journal Citation Reports (JCR) 这是个评估科学和技术期刊影响力的重要工具。通过查看影响因子和其他指标,可以帮助确定哪些测绘遥感领域的期刊最具权威性并且属于SCI范畴。 咨询图书馆员或专业人士 大学或研究机构的专业人员能够提供指导和支持,帮助定位最适合需求的具体期刊名称及详情。 订阅行业通讯和服务 某些服务如Elsevier's Scopus也会报告关于各个学科顶级期刊的消息,保持关注可以获得及时的通知。 以下是几个知名的测绘遥感相关SCI期刊的例子: - Remote Sensing of Environment - IEEE Transactions on Geoscience and Remote Sensing - ISPRS Journal of Photogrammetry and Remote Sensing - International Journal of Applied Earth Observation and Geoinformation 请注意,实际的SCI期刊名单可能会随着时间而变化,因此建议总是使用最新的在线资源来进行确认。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值