日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

《ASP.NET Core 微服务实战》-- 读书笔记(第10章)

發(fā)布時間:2023/12/4 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《ASP.NET Core 微服务实战》-- 读书笔记(第10章) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

第 10 章 應(yīng)用和微服務(wù)安全

云應(yīng)用意味著應(yīng)用運行所在的基礎(chǔ)設(shè)施無法掌控,因此安全不能再等到事后再考慮,也不能只是檢查清單上毫無意義的復(fù)選框

由于安全與云原生應(yīng)用密切相關(guān),本章將討論安全話題,并用示例演示幾種保障 ASP.NET Core Web 應(yīng)用和微服務(wù)安全的方法

云環(huán)境中的安全

內(nèi)網(wǎng)應(yīng)用

企業(yè)一直在開發(fā)這種支持性的應(yīng)用,但當(dāng)我們需要基于運行在可縮放的云基礎(chǔ)設(shè)施之的 PaaS 開發(fā)此類應(yīng)用時,很多舊的模式和實踐將很快失效

一個最明顯的問題就是無法支持 Windows 身份驗證

長期以來,ASP.NET 開發(fā)人員一直沉浸在借助內(nèi)置的 Windows 憑據(jù)來保障 Web 應(yīng)用安全的便利中

不管是公有云平臺還是私有部署的 PaaS 平臺,在這些平臺上,支撐應(yīng)用的操作系統(tǒng)應(yīng)被視為臨時存續(xù)的

有些企業(yè)的安全策略要求所有虛擬機在滾動更新期間需要銷毀并重新構(gòu)建,從而縮小持續(xù)攻擊的可能范圍

Cookie 和 Forms 身份驗證

當(dāng)應(yīng)用運行于 PaaS 環(huán)境中時,Cookie 身份驗證仍然適用

不過它也會給應(yīng)用增加額外負擔(dān)

首先,Forms 身份驗證要求應(yīng)用對憑據(jù)進行維護并驗證

也就是說,應(yīng)用需要處理好這些保密信息的安全保障、加密和存儲

云環(huán)境中的應(yīng)用內(nèi)加密

在傳統(tǒng) ASP.NET 應(yīng)用開發(fā)中,常見的加密使用場景是創(chuàng)建安全的身份驗證 Cookie 和會話 Cookie

在這種加密機制中,Cookie 加密時會用到機器密鑰

然后當(dāng) Cookie 由瀏覽器發(fā)回 Web 應(yīng)用時,再使用同樣的機器密鑰對其進行解密

如果無法依賴持久化文件系統(tǒng),又不可能在每次啟動應(yīng)用時將密鑰置于內(nèi)存中,這些密鑰將如何存儲

答案是,將加密密鑰的存儲和維護視為后端服務(wù)

也就是說,與狀態(tài)維持機制、文件系統(tǒng)、數(shù)據(jù)庫和其他微服務(wù)一樣,這個服務(wù)位于應(yīng)用之外

Bearer 令牌

本章的示例將講解 OAuth 和 OpenID Connect (簡稱 OIDC)

如果要以 HTTP 友好、可移植的方式傳輸身份證明,最常見的方法就是 Bearer 令牌

應(yīng)用從 Authorization 請求頭接收 Dearer 令牌

下例展示一個包含 Bearer 令牌的 HTTP 跟蹤會話

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 (XLL; Linux x86_64) etc...etc...etc...

Authorization 請求頭的值中包含一個表示授權(quán)類型的單詞,緊接著是包含憑據(jù)的字符序列

通常,服務(wù)在處理 Bearer 令牌時,會從 Authorization 請求頭提取令牌

很多各式的令牌,例如 OAuth 2.0 (JWT),通常將 Base64 編碼用作一種 URL 友好格式,因此驗證令牌的第一步就是解碼,以獲取原有內(nèi)容

如果令牌使用私鑰加密,服務(wù)就需要使用公鑰驗證令牌確實由正確的發(fā)行方頒發(fā)

ASP.NET Core Web 應(yīng)用安全

本章示例中,我們將主要關(guān)注 OpenID Connetc 和 JWT 格式的 Bearer 令牌

OpenID Connect 基礎(chǔ)

OpenID Connect 是 OAuth2 的一個超集,它規(guī)定了身份提供方(IDP)、用戶和應(yīng)用之間的安全通信的規(guī)范和標準

使用 OIDC 保障 ASP.NET Core 應(yīng)用的安全

作為本章第一個代碼清單,我們將使用 OIDC 為一個簡單的 ASP.NET Core
MVC Web 應(yīng)用提供安全保障功能

創(chuàng)建一個空的 Web 應(yīng)用

$ dotnet new mvc

使用 Auth0 賬號配置身份提供方服務(wù)

現(xiàn)在可轉(zhuǎn)到 http://auth0.com/,注冊完成后進入面板,點擊“創(chuàng)建客戶端”按鈕,請確保應(yīng)用類型選擇為“常規(guī) Web 應(yīng)用”

選擇 ASP.NET Core 作為實現(xiàn)語言后,將轉(zhuǎn)到一個 “快速開始”教程,其代碼與本章將要編寫的內(nèi)容非常相似

使用 OIDC 中間件

GitHub鏈接:https://github.com/microservices-aspnetcore/secure-services

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: false, reloadOnChange: false).AddEnvironmentVariables();Configuration = builder.Build();}public IConfigurationRoot Configuration { get; }// This method gets called by the runtime. Use this method to add services to the container.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"));}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.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);}};}} }

與之前各章代碼的第一點區(qū)別在于,我們創(chuàng)建了一個名為 OpenIdSettings 的選項類,從配置系統(tǒng)讀入后,以 DI 的服務(wù)方式提供給應(yīng)用

它是一個簡單類,其屬性僅用于存儲每種 OIDC 客戶端都會用到的四種元信息:

  • 授權(quán)域名

  • 客戶端 ID

  • 客戶端密鑰

  • 回調(diào) URL

由于這些信息的敏感性,我們的 appsettings.json 文件沒有簽入到 GitHub,不過以下代碼清單列出了它的大致格式

{"OpenID": {"Domain": "Your Auth0 domain","ClientId": "Your Auth0 Client Id","ClientSecret": "Your Auth0 Client Secret","CallbackUrl": "http://localhost:5000/signin-auth0"} }

接下來要在 Startup 類中執(zhí)行的兩部操作是,讓 ASP.NET Core 使用 Cookie 身份驗證和 OpenID Connect 身份驗證

添加一個 account 控制器,提供的功能包括登錄、注銷、以及使用一個視圖顯示用戶身份中的所有特征

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();}} }

Claims 視圖代碼,它從特征集合中逐個取出特征的類型和值,并呈現(xiàn)在表格中,同時,視圖還顯示用戶頭像

<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>

現(xiàn)在,我們已經(jīng)基于一個模板生成的空白 ASP.NET Core Web 應(yīng)用,建立了與第三方云友好的身份提供服務(wù)的連接

這讓云應(yīng)用能夠利用 Bearer 令牌和 OIDC 標準的優(yōu)勢,從手工管理身份驗證的負擔(dān)中解放出來

OIDC 中間件和云原生

我們已經(jīng)討論過在使用 Netflix OSS 技術(shù)棧時,如何借助 Steeltoe 類庫支持應(yīng)用配置和服務(wù)發(fā)現(xiàn)

我們可以使用來自 Steeltoe 的 NuGet 模塊 Steeltoe.Security.DataProtection.Redis

它專門用于將數(shù)據(jù)保護 API 所用的存儲從本地磁盤遷移到外部的 Redis 分布式緩存中

在這個類庫,可使用以下方式在 Startup 類的 ConfigureServices 方法中配置由外部存儲支持的數(shù)據(jù)保護功能

services.AddMvc();services.AddRedisConnectionMultiplexer(Configuration); services.AddDataProtection().PersisitKeysToRedis().SetApplicationName("myapp-redis-keystore");services.AddDistributedRedisCache(Configuration);services.AddSession();

接著,我們在 Configure 方法中調(diào)用 app.UseSession() 以完成外部會話狀態(tài)的配置

保障 ASP.NET Core 微服務(wù)的安全

本節(jié),我們討論為微服務(wù)提供安全保障的幾種方法,并通過開發(fā)一個使用 Bearer 令牌提供安全功能的微服務(wù)演示其中的一種方法

使用完整 OIDC 安全流程保障服務(wù)的安全

在這個流程中,用戶登錄的流程前面已經(jīng)討論過,即通過幾次瀏覽器重定向完成網(wǎng)站和 IDP 之間的交互

當(dāng)網(wǎng)站獲取到合法身份后,會向 IDP 申請訪問令牌,申請時需要提供身份證令牌以及正在被請求的資源的信息

使用客戶端憑證保障服務(wù)的安全

首先,只允許通過 SSL 與服務(wù)通信

此外,消費服務(wù)的代碼需要在調(diào)用服務(wù)時附加憑據(jù)

這種憑據(jù)通常就是用戶名和密碼

在一些不存在人工交互的場景中,將其稱為客戶端標識和客戶端密鑰更準確

使用 Bearer 令牌保障服務(wù)的安全

在服務(wù)的 Startup 類型的 Configure 方法中啟用并配置 JWT Bearer 身份驗證

app.UseJwtBearerAuthentication(new JwtBearerOptions) {AutomaticAuthenticate = true,AutomaticChallenge = true,TokenValidationParameters = new TokenValidationParameters{ValidateIssuerSigningKey = true,IssuerSigningKey = signingKey,ValidateIssuer = false,ValidIssuer = "http://fake.issuer.com",ValidateAudience = false,ValidAudience = "http://sampleservice.example.com",ValidateLifetime = true,} };

我們可控制在接收 Bearer 令牌期間要執(zhí)行的各種驗證,包括頒發(fā)方簽名證書、頒發(fā)方名稱、接收名稱以及令牌的時效

在上面的代碼中,我們禁用了頒發(fā)方和接收方名稱驗證,其過程都是相當(dāng)簡單的字符串對比檢查

開啟驗證時,頒發(fā)方和接收方名稱必須與令牌中包含的頒發(fā)方式和接收方式名稱嚴格匹配

要創(chuàng)建一個密鑰,用于令牌簽名時所用的密鑰進行對比,我們需要一個保密密鑰,并從它創(chuàng)建一個 SymmetricSecurityKey

string SecretKey = "sericouslyneverleavethissitting in yourcode"; SymmetricSecurityKey signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));

為了消費安全的服務(wù),我們需要創(chuàng)建一個簡單的控制臺應(yīng)用,它從一組 Claim 對象生成一個 JwtSecurityToken 實例,并作為 Bearer 令牌放入 Authorization 請求頭發(fā)給服務(wù)端

var claims = new [] {new Claim(JwtRegisteredClaimNames.Sub, "AppUser_Bob"),new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(DataTime.Now).ToString(), ClaimValueTypes.Integer64), }; var jwt = new JwtSecurityToken(issuer : "issuer",audience : "audience",claims : claims,notBefore : DateTiem.UtcNow,expires : DateTime.UtcNow.Add(TimeSpan.FromMinutes(20)),signingCredentials: creds) httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", encodedJwt);var result = httpClient.GetAsync("http://localhost:5000/api/secured").Result; Console.WriteLine(result.StatusCode); Console.WriteLine(result.Content.ToString());

下面是一個受安全機制保護的控制器方法,它將枚舉從客戶端發(fā)來的身份特征

[Authorize] [HttpGet] public string Get() {foreach (var claim in HttpContext.User.Claims){Console.WriteLine($"{claim.Type}:{claim.Value}");}return "this is from the super secret area"; }

如果要控制特定客戶端能夠訪問的控制器方法,我們可以利用策略概念,策略是在授權(quán)檢查過程中執(zhí)行一小段代碼

[Authorize( Policy = "CheeseburgerPolicy")] [HttpGet("policy")] public string GetWithPolicy() {return "this is from the super secret area w/policy enforcement."; }

在 ConfigureServices 方法中配置策略的過程很簡單

public void ConfigureServices(IServiceCollection services){services.AddMvc();services.AddOptions();services.AddAuthorization( options => {options.AddPolicy("CheeseburgePolicy",policy =>policy.RequireClaim("icanhazcheeseburger", "true"));}); }

現(xiàn)在,只要修改控制臺應(yīng)用,在其中添加這種類型的特征并將值指定為 true,就既能調(diào)用普通受保護的控制器方法,又能調(diào)用標記了 CheeseburgerPolicy 策略的方法

該策略需要特定的身份特征、用戶名、條件以及角色

還可以通過實現(xiàn) IAuthorizationRequirement 接口定義定制的需求,這樣就可以添加自定義驗證邏輯而不會影響各個控制器

總結(jié)

以上是生活随笔為你收集整理的《ASP.NET Core 微服务实战》-- 读书笔记(第10章)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。