Slide 1

Slide 1 text

ASP.NET Core & MVC 2 Security Overview Dominick Baier @leastprivilege

Slide 2

Slide 2 text

2 @leastprivilege Me • Independent Consultant – Specializing on Application Security Architectures – Working with Software Development Teams (ISVs and in-house) • Creator and Maintainer of IdentityServer OSS Project – Certified OpenID Connect & OAuth 2.0 Implementation for .NET – https://identityserver.io email [email protected] blog http://leastprivilege.com twitter @leastprivilege slides https://speakerdeck.com/leastprivilege

Slide 3

Slide 3 text

Modern Application Architecture Browser Native App Server App/Thing Web App Service Service Service Identity

Slide 4

Slide 4 text

4 @leastprivilege .NET Timeline 2002 .NET 1.0 ASP.NET 1.0 2006 .NET 3.0 WCF (#fail) 2009 WIF 2012 .NET 4.5 2013 Katana 2.0 2014 Katana 3.0 2016 .NET Core ASP.NET Core v1 Claims + Security Token Support = External Authentication 2017 .NET Core ASP.NET Core v2

Slide 5

Slide 5 text

5 @leastprivilege The new .NET

Slide 6

Slide 6 text

6 @leastprivilege ASP.NET Core Architecture • ASP.NET Core is the HTTP runtime • MVC is Microsoft's primary application framework – combines web UI & API Console Application .NET (Core) ASP.NET Core Middleware Middleware User Agent MVC DI

Slide 7

Slide 7 text

7 @leastprivilege ASP.NET Core Security on a single Slide • Everything is based on ClaimsPrincipal – no more custom IPrincipal • It's all about services – authentication – authorization – claims transformation – data protection – anti-forgery – CORS – encoding • Middleware for automatic per-request invocation

Slide 8

Slide 8 text

8 @leastprivilege Authentication in ASP.NET Core • Handlers in DI implement specific authentication methods – Cookies for browser based authentication – Google, Facebook, and other social authentication* – OpenId Connect for external authentication – JSON web token (JWT) for token-based authentication • Middleware invokes handlers for request related processing – handlers can be also invoked manually * 20+ more https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers

Slide 9

Slide 9 text

9 @leastprivilege Interacting with the authentication system • Extension methods on HttpContext call the IAuthenticationService in DI 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 AuthenticateAsync(this HttpContext context) { } public static Task AuthenticateAsync(this HttpContext context, string scheme) { } }

Slide 10

Slide 10 text

10 @leastprivilege Setting up authentication • Global settings go into DI – e.g. default schemes • Authentication middleware invokes handlers public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(); } public void Configure(IApplicationBuilder app) { app.UseAuthentication(); }

Slide 11

Slide 11 text

11 @leastprivilege Cookie Authentication 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; }); }

Slide 12

Slide 12 text

12 @leastprivilege Cookies: Logging in • SignInAsync issues cookie – either using a named scheme, or default var claims = new Claim[] { new Claim("sub", "37734"), new Claim("name", "Brock Allen") }; var ci = new ClaimsIdentity(claims, "password", "name", "role"); var cp = new ClaimsPrincipal(ci); await HttpContext.SignInAsync(cp);

Slide 13

Slide 13 text

13 @leastprivilege Cookies: Logging out • SignOutAsync removes cookie await HttpContext.SignOutAsync();

Slide 14

Slide 14 text

14 @leastprivilege Data Protection • Who thought this would be a good idea?? For giggles: "https://www.google.com/#q=

Slide 15

Slide 15 text

15 @leastprivilege Data Protection • Used to protect cookies and other secrets – IDataProtectionProvider in DI • Uses a key container file – stored outside of application directory* – uses a key ring with automatic rotation – keys should be protected • Needs to be synchronized between nodes in a farm * https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/default-settings

Slide 16

Slide 16 text

16 @leastprivilege Claims Transformation • Per-request manipulation of principal & claims – register an instance of IClaimsTransformation in DI – gets called from the handler's AuthenticateAsync method public class ClaimsTransformer : IClaimsTransformation { public async Task TransformAsync(ClaimsPrincipal principal) { return await CreateApplicationPrincipalAsync(principal); } } services.AddTransient();

Slide 17

Slide 17 text

17 @leastprivilege Authorization • Complete re-write – better separation of business code and authorization logic – policy based authorization – resource/action based authorization – DI enabled ASP.NET 4.x version: https://github.com/DavidParks8/Owin-Authorization

Slide 18

Slide 18 text

18 @leastprivilege [Authorize] • Similar syntax – roles still supported [Authorize] public class HomeController : Controller { [AllowAnonymous] public IActionResult Index() { return View(); } [Authorize(Roles = "Sales")] public IActionResult About() { return View(User); } }

Slide 19

Slide 19 text

19 @leastprivilege Authorization policies 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

Slide 20

Slide 20 text

20 @leastprivilege Programmatically using policies public class CustomerController : Controller { private readonly IAuthorizationService _authz; public CustomerController(IAuthorizationService authz) { _authz = authz; } public async Task Manage() { var result = await _authz.AuthorizeAsync(User, "ManageCustomers"); if (result.Succeeded) return View(); return Forbid(); } }

Slide 21

Slide 21 text

21 @leastprivilege …or from a View @using Microsoft.AspNetCore.Authorization @inject IAuthorizationService _authz @if ((await _authz.AuthorizeAsync(User, "ManageCustomers")).Succeeded) { }

Slide 22

Slide 22 text

22 @leastprivilege Custom Requirements public class JobLevelRequirement : IAuthorizationRequirement { public JobLevel Level { get; } public JobLevelRequirement(JobLevel level) { Level = level; } } public static class StatusPolicyBuilderExtensions { public static AuthorizationPolicyBuilder RequireJobLevel( this AuthorizationPolicyBuilder builder, JobLevel level) { builder.AddRequirements(new JobLevelRequirement(level)); return builder; } }

Slide 23

Slide 23 text

23 @leastprivilege Handling Requirements public class JobLevelRequirementHandler : AuthorizationHandler { 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); } } }

Slide 24

Slide 24 text

24 @leastprivilege Resource-based Authorization Subject Object Operation - client ID - subject ID - scopes - more claims + DI - read - write - send via email - ... - ID - owner - more properties + DI

Slide 25

Slide 25 text

25 @leastprivilege Example: Document resource public class DocumentAuthorizationHandler : AuthorizationHandler { public override Task HandleRequirementAsync( AuthorizationHandlerContext context, OperationAuthorizationRequirement operation, Document resource) { // authorization logic } } services.AddTransient(); Add handler in DI:

Slide 26

Slide 26 text

26 @leastprivilege Invoking the authorization handler public class DocumentController : Controller { private readonly IAuthorizationService _authz; public DocumentController(IAuthorizationService authz) { _authz = authz; } public async Task Update(Document doc) { if ((await _authz.AuthorizeAsync(User, doc, Operations.Update)).Failure) { return Forbid(); } // do stuff } }

Slide 27

Slide 27 text

27 @leastprivilege Summary: Cookies & Authorization Browser sends request Authentication middleware checks DefaultAuthenticate scheme Default authenticate handler calls AuthenticateAsync Cookie found? Populate HttpContext.User Request arrives at Controller [Authorize] ? Execute action method Get current user or call handler based on specified scheme AuthZ filter calls Challenge and redirects to LoginPath Is user authenticated? Account controller authenticates user and redirects back Is user authorized? AuthZ filter calls Forbid and redirects to AccessDeniedPath yes no yes no no yes no yes

Slide 28

Slide 28 text

28 @leastprivilege External Authentication • ASP.NET Core supports – Google, Twitter, Facebook, Microsoft Account – OpenID Connect & JSON Web Tokens • New generic OAuth 2.0 handler makes integration with other proprietary providers easier – LinkedIn, Slack, Spotify, WordPress, Yahoo, Github, Instragram, BattleNet, Dropbox, Paypal, Vimeo… https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers

Slide 29

Slide 29 text

29 @leastprivilege Social Identity Providers • Enabled with AddGoogle, et al. – Rely upon cookie authentication handler services.AddAuthentication("Cookies") .AddCookie("Cookies", options => { options.LoginPath = "/account/login"; options.AccessDeniedPath = "/account/denied"; }) .AddGoogle("Google", options => { options.SignInScheme = "Cookies"; options.ClientId = "..."; options.ClientSecret = "..."; });

Slide 30

Slide 30 text

30 @leastprivilege Social Identity Providers • Challenge triggers redirect for login – Control URL user returns to and state with AuthenticationProperties – MVC ChallengeResult works with action result architecture var props = new AuthenticationProperties { RedirectUri = "/Home/Secure" }; await HttpContext.ChallengeAsync("Google", props); // or if using MVC: return Challenge("Google", props);

Slide 31

Slide 31 text

31 @leastprivilege Summary: External Authentication 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

Slide 32

Slide 32 text

32 @leastprivilege Mixing local and external Authentication • Typically need provisioning logic for users from social providers – Use additional cookie handler for processing registration services.AddAuthentication("Cookies") .AddCookie("Cookies", options => { options.LoginPath = "/account/login"; options.AccessDeniedPath = "/account/denied"; }) .AddCookie("Temp") .AddGoogle("Google", options => { options.SignInScheme = "Temp"; options.ClientId = "..."; options.ClientSecret = "..."; });

Slide 33

Slide 33 text

33 @leastprivilege Mixing local and external Authentication • Redirect page performs local account registration logic – AuthenticateAsync triggers cookie middleware – Create local account or load existing account – Use primary cookie middleware to log user in (and remove temp cookie) var tempUser = (await HttpContext.AuthenticateAsync("Temp")).Principal; var userIdClaim = tempUser.FindFirst(ClaimTypes.NameIdentifier); var provider = userIdClaim.Issuer; var userId = userIdClaim.Value; // create local account if new, or load existing local account var user = new ClaimsPrincipal(...); await HttpContext.SignInAsync(user); await HttpContext.SignOutAsync("Temp");

Slide 34

Slide 34 text

34 @leastprivilege Summary: External Authentication with Callback 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 temporary cookie containing external identity) Run app-level post- processing SignOut temp cookie SignIn primary cookie Redirect to final URL

Slide 35

Slide 35 text

35 @leastprivilege The way forward… Browser Native App Server App "Thing" Web App Web API Web API Web API Security Token Service Authentication, SSO, account linking, federation, social logins…

Slide 36

Slide 36 text

36 @leastprivilege Security Protocols Browser Native App Server App "Thing" Web App Web API Web API Web API OpenID Connect OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 Security Token Service OpenID Connect OpenID Connect

Slide 37

Slide 37 text

37 @leastprivilege http://openid.net/connect/

Slide 38

Slide 38 text

38 @leastprivilege OpenID Connect handler services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; } .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "https://demo.identityserver.io"; options.ClientId = "mvc"; });

Slide 39

Slide 39 text

39 @leastprivilege Access Token Validation • JWT bearer token authentication handler public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "https://your_oidc_provider"; options.Audience = "your_api_identifier"; }); }

Slide 40

Slide 40 text

40 @leastprivilege Issuing Tokens https://docs.microsoft.com/en-us/aspnet/core/security/authentication/community

Slide 41

Slide 41 text

41 @leastprivilege Certified OpenID Connect Provider

Slide 42

Slide 42 text

42 @leastprivilege

Slide 43

Slide 43 text

43 @leastprivilege Resources • https://github.com/leastprivilege/ – AspNetCoreSecuritySamples • https://github.com/dotnet – corefx – coreclr • https://github.com/aspnet – home – security – announcements • https://docs.asp.net • https://identityserver.io

Slide 44

Slide 44 text

44 @leastprivilege thank you!