Share
Embed
Transcript
33 slides
-
Securing Web Applications and APIs with ASP.NET Core 2.2 and
3.0 Dominick Baier @leastprivilege -
2 @leastprivilege / @brocklallen Me • Independent Consultant – Specializing
on Application Security Architectures – Working with Software Development Teams (ISVs and in-house) • Co-Creator of IdentityServer & IdentityModel OSS Project – Certified OpenID Connect & OAuth 2.0 Implementation for .NET – https://identityserver.io • Co-Creator of PolicyServer – Modern Authorization Solution – https://policyserver.io email [email protected] blog http://leastprivilege.com twitter @leastprivilege slides https://speakerdeck.com/leastprivilege -
Modern Application Architecture Browser Native App Server App/Thing Web App
Service Service Service Identity Provider Authorization Policy Provider -
6 @leastprivilege / @brocklallen Agenda • Hosting • Data Protection
• Authentication • Authorization • Identity • IdentityServer integration https://github.com/leastprivilege/AspNetCoreSecuritySamples -
7 @leastprivilege / @brocklallen Hosting HTTPS HTTPS HTTP/HTTPS Using a
reverse proxy Edge Kestrel Kestrel -
8 @leastprivilege / @brocklallen Kestrel Security • HTTPS by default
– static configuration or dynamic selection (SNI) – dotnet dev-certs tool for local development • Need to fine-tune transport parameters when doing edge hosting – Keep-Alive timeouts – Request Header limits – Request/Response buffer sizes – Request line size – Request header limits – Request header count limits – Request/Response body timeouts & data rates – Total client connections – Handshake timeous – … -
9 @leastprivilege / @brocklallen ASP.NET Core Architecture • Host •
Pipeline & middleware • Services Console Application .NET (Core) ASP.NET Core Middleware Middleware User Agent MVC DI -
10 @leastprivilege / @brocklallen Data Protection • Remember this? <system.web>
<!– copied from the 90ies --> <machineKey decryptionKey="656E7...617365206865726547A5" validationKey="07C1493415E4405F08...6EF8B1F" /> </system.web> For giggles: "https://www.google.com/#q=<machineKey filetype:config" -
11 @leastprivilege / @brocklallen Data Protection in ASP.NET Core •
Keys are stored outside of application directory – profile – registry – Azure web apps magic – Redis – manual • Automatic key management – 512 bit master key / AES-256 CBC / HMACSHA256 – rotated every 90 days – automatic application isolation • Key protection – DPAPI, X509, Azure KeyVault -
13 @leastprivilege / @brocklallen Who uses Data Protection? • ASP.NET
Core – protecting cookies – anti-forgery – protecting OpenID Connect/OAuth state – [TempData] • You – IDataProtectionProvider service – can be also used with non-ephemeral data • if key ring is properly stored / backed-up -
14 @leastprivilege / @brocklallen Authentication in ASP.NET Core • Authenticating
users/clients – local – Google, Facebook, and other proprietary providers* – OpenID Connect, WS-Federation & SAML** for standards-based external authentication – JSON web token (JWT) for token-based API authentication • Session Management – cookies * 40+ more https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers ** https://github.com/Sustainsys/Saml2 -
15 @leastprivilege / @brocklallen Setting up authentication public void ConfigureServices(IServiceCollection
services) { services.AddAuthentication(defaultScheme: "cookies") .AddCookies(scheme: "cookies") .AddGoogle(scheme: "google") .AddOpenIdConnect(scheme: "idsrv"); } public void Configure(IApplicationBuilder app) { app.UseAuthentication(); } -
16 @leastprivilege / @brocklallen Interacting with the authentication system public
interface IAuthenticationService { // authenticate the specified scheme. Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme); // session management Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties); Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties); // signal that authentication is required Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties); // signal that access is denied Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties); } -
17 @leastprivilege / @brocklallen Interacting with the authentication system (2)
• Convenience extension methods public static class AuthenticationHttpContextExtensions { public static Task SignInAsync(this HttpContext context, ClaimsPrincipal principal) { } public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal) { } public static Task SignOutAsync(this HttpContext context) { } public static Task SignOutAsync(this HttpContext context, string scheme) { } public static Task ChallengeAsync(this HttpContext context) { } public static Task ChallengeAsync(this HttpContext context, string scheme) { } public static Task ForbidAsync(this HttpContext context) { } public static Task ForbidAsync(this HttpContext context, string scheme) { } public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context) { } public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context, string scheme) { } } -
18 @leastprivilege / @brocklallen Session Management (1) public void ConfigureServices(IServiceCollection
services) { services.AddAuthentication(defaultScheme: "Cookies") .AddCookie("Cookies", options => { options.LoginPath = "/account/login"; options.AccessDeniedPath = "/account/denied"; options.Cookie.Name = "myapp"; options.Cookie.Expiration = TimeSpan.FromHours(8); options.SlidingExpiration = false; options.Cookie.SameSite = SameSiteMode.Lax; }); } -
19 @leastprivilege / @brocklallen Session Management (2) • Cookie contains
– claims – metadata var claims = new List<Claim> { new Claim("sub", "123"), new Claim("name", "Bob") }; var ci = new ClaimsIdentity(claims, "password", "name", "role"); var props = new AuthenticationProperties { Items = { { "token", "abc" } } }; await HttpContext.SignInAsync(new ClaimsPrincipal(ci), props); await HttpContext.SignOutAsync(); -
20 @leastprivilege / @brocklallen Advanced Features • The cookie handler
has an eventing model – additional validation on incoming cookie – redirect/sign-in/sign-out interception – sign-out cleanup • Session storage mechanism can be replaced – e.g. server-side (Redis, Cosmos DB..) – keeps cookies small – allows for server-side revocation https://leastprivilege.com/2019/01/14/automatic-oauth-2-0-token-management-in-asp-net-core/ -
21 @leastprivilege / @brocklallen External Authentication • Special type of
authentication handler – RemoteAuthenticationHandler – ChallengeAsync sends authentication/token request – SignOutAsync sends sign-out request – provides callback endpoints to process protocol responses Challenge(scheme) Handler's ChallengeAsync method gets invoked Redirect to external provider External provider Authentication middleware asks handlers who wants to process request callback Handlers does the protocol post- processing Call sign-in handler (sets cookie containing external identity) Redirect to final URL -
22 @leastprivilege / @brocklallen Example: Sign-in & Token Request w/
OpenID Connect services.AddAuthentication(options => { options.DefaultScheme = "cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "https://demo.identityserver.io"; options.ClientId = "server.hybrid"; options.ClientSecret = "secret"; options.ResponseType = "code id_token"; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("api"); }); -
23 @leastprivilege / @brocklallen API Authentication • Built-in support for
JWT bearer tokens – see https://github.com/IdentityModel/IdentityModel.AspNetCore.OAuth2Introspection for RFC 7662 support public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("jwt") .AddJwtBearer("jwt", options => { options.Authority = "https://demo.identityserver.com"; options.Audience = "api" }); } -
24 @leastprivilege / @brocklallen Authorization • Policy-based authorization – based
on properties of the caller/user • Resource-based authorization – takes the resource that is being manipulated into account as well • Authorization is a service – DI based – extensible – testable • Will be also available as middleware in 3.0 https://github.com/blowdart/AspNetAuthorizationWorkshop -
25 @leastprivilege / @brocklallen Example Authorization Policy services.AddAuthorization(options => {
options.AddPolicy("ManageCustomers", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("department", "sales"); policy.RequireClaim("status", "senior"); }); }); [Authorize("ManageCustomers")] public IActionResult Manage() { // stuff } Startup Controller -
26 @leastprivilege / @brocklallen Programmatically using policies public class CustomerController
: Controller { private readonly IAuthorizationService _authz; public CustomerController(IAuthorizationService authz) { _authz = authz; } public async Task<IActionResult> Manage() { var result = await _authz.AuthorizeAsync(User, "ManageCustomers"); if (result.Succeeded) return View(); return Forbid(); } } -
27 @leastprivilege / @brocklallen Custom Authorization Handler public class JobLevelRequirementHandler
: AuthorizationHandler<JobLevelRequirement> { private readonly IOrganizationService _service; public JobLevelRequirementHandler(IOrganizationService service) { _service = service; } protected override void Handle( AuthorizationContext context, JobLevelRequirement requirement) { var currentLevel = _service.GetJobLevel(context.User); if (currentLevel == requirement.Level) { context.Succeed(requirement); } } } -
28 @leastprivilege / @brocklallen Resource-based Authorization Subject Object Operation -
client ID - subject ID - scopes - more claims + DI - read - write - send via email - ... - ID - owner - more properties + DI -
29 @leastprivilege / @brocklallen Example: Document resource public class DocumentAuthorizationHandler
: AuthorizationHandler<OperationAuthorizationRequirement, Document> { public override Task HandleRequirementAsync( AuthorizationHandlerContext context, OperationAuthorizationRequirement operation, Document resource) { // authz logic } } -
30 @leastprivilege / @brocklallen Invoking the authorization handler public class
DocumentController : Controller { private readonly IAuthorizationService _authz; public DocumentController(IAuthorizationService authz) { _authz = authz; } public async Task<IActionResult> Update(Document doc) { if ((await _authz.AuthorizeAsync(User, doc, Operations.Update)).Failure) { return Forbid(); } // do stuff } } -
31 @leastprivilege / @brocklallen ASP.NET Identity • Library for managing
identity data for users – manages credentials (e.g. passwords, complexity) – lockout for brute force prevention – mapping external authentication • Stores this data in database – can be used to maintain additional user attributes/claims • Provides primitives for email confirmation, password reset, and MFA workflows • Abstraction on cookie authentication handler – sign-in/sign-out -
32 @leastprivilege / @brocklallen The missing link • ASP.NET Identity
templates are geared towards local authentication • IdentityServer adds OpenID Connect & OAuth 2.0 for remote authentication • ASP.NET Core 2.2 + ships with an IdentityServer integration library – "zero config" IdentityServer using ASP.NET Identity & local APIs – Web API and SPA template • Will be expanded to more advanced scenarios in 3.0 – separating IdentityServer from APIs – dynamic client registration -
33 @leastprivilege / @brocklallen Thanks! …and (because I always forget)
- we have stickers!