Upgrade to Pro — share decks privately, control downloads, hide ads and more …

.NET Core, ASP.NET Core & MVC - Security Overview

.NET Core, ASP.NET Core & MVC - Security Overview

Updated for SDD 2017

Dominick Baier

May 14, 2017
Tweet

More Decks by Dominick Baier

Other Decks in Programming

Transcript

  1. 2 @leastprivilege Me • Independent Consultant – Specializing in Identity

    & Access Control – Working with Software Development Teams (ISVs and in-house) • Creator and Maintainer of IdentityServer OSS Project – Certified OpenID Connect & OAuth 2.0 Implementation for ASP.NET – https://identityserver.io [email protected] http://leastprivilege.com slides: https://speakerdeck.com/leastprivilege
  2. 5 @leastprivilege Platform specific Implementation where needed AES.Create() OpenSSL Windows

    CNG Apple Crypto .NET API Surface Platform Abstraction Layer
  3. 7 @leastprivilege Initial Design public interface IIdentity { bool IsAuthenticated

    { get; } string AuthenticationType { get; } string Name { get; } } public interface IPrincipal { IIdentity Identity { get; } bool IsInRole(string roleName); }
  4. 8 @leastprivilege Dealing with identity (old school) Plumbing code /

    Infrastructure / Runtime Application logic Thread.CurrentPrincipal set get TLS Application
  5. 9 @leastprivilege Updates to Identity over Time 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 Claims + Security Token Support = External Authentication
  6. 10 @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
  7. 11 @leastprivilege Security Architecture in ASP.NET Core • Everything is

    based on ClaimsPrincipal – no more custom IPrincipal • Authentication is implemented as middleware – cookies – external authentication • Other security related services – CORS, logging, encoding, anti-forgery • New data protection API • New authorization API
  8. 12 @leastprivilege Authentication in ASP.NET Core • Various middleware provide

    authentication features – Cookies for browser based authentication – Google, Facebook, and other social authentication – OpenId Connect for external authentication – JSON web token (JWT) for token-based authentication
  9. 13 @leastprivilege AuthenticationManager • Central API for coordinating authentication middleware

    – availabe via HttpContext public abstract class AuthenticationManager { public abstract IEnumerable<AuthenticationDescription> GetAuthenticationSchemes(); public virtual Task SignInAsync(string authenticationScheme, ClaimsPrincipal principal); public virtual Task SignOutAsync(string authenticationScheme); public virtual Task<ClaimsPrincipal> AuthenticateAsync(string authenticationScheme); public virtual Task ChallengeAsync(string authenticationScheme); public virtual Task ForbidAsync(); // ... }
  10. 14 @leastprivilege Cookie Authentication Middleware • Forms / Session authentication

    replacement public void Configure(IApplicationBuilder app) { app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = "Cookies", AutomaticAuthenticate = true, AutomaticChallenge = true, LoginPath = new PathString("/Account/Login"), AccessDeniedPath = new PathString("/Account/AccessDenied") }); }
  11. 15 @leastprivilege Cookies: Logging in • SignInAsync issues cookie –

    Authentication scheme parameter indicates which middleware var claims = new Claim[] { new Claim("sub", "37734"), new Claim("name", "Dominick Baier") }; var ci = new ClaimsIdentity(claims, "password"); var cp = new ClaimsPrincipal(ci); await HttpContext.Authentication.SignInAsync("Cookies", cp);
  12. 16 @leastprivilege Cookies: Logging out • SignOutAsync removes cookie –

    Authentication scheme parameter indicates which middleware await HttpContext.Authentication.SignOutAsync("Cookies");
  13. 17 @leastprivilege Data Protection • Who thought this would be

    a good idea?? For giggles: "https://www.google.com/#q=<machineKey filetype:config" <system.web> <!– copied from http://machinekeys.ru seemed legit --> <machineKey decryptionKey="656E7...617365206865726547A5" validationKey="07C1493415E4405F08...6EF8B1F" /> </system.web>
  14. 18 @leastprivilege Key Container Locations • On Azure Web Apps

    (no encryption) – %HOME%\ASP.NET\DataProtection-Keys • If user profile is loaded (encrypted) – %LOCALAPPDATA%\ASP.NET\DataProtection-Keys • IIS / no profile (encrypted) – Registry HKLM • In-Memory • Manual configuration <?xml version="1.0" encoding="utf-8"?> <key id="eacc6495-83a3-4aaf-ad29-fee164c69963" version="1"> <creationDate>2015-05-02T08:20:38.6577127Z</creationDate> <activationDate>2015-05-02T08:20:38.6424674Z</activationDate> <expirationDate>2015-07-31T08:20:38.6424674Z</expirationDate> <descriptor> <descriptor> <encryption algorithm="AES_256_CBC" /> <validation algorithm="HMACSHA256" /> <encryptedSecret> <encryptedKey xmlns=""> <!-- This key is encrypted with Windows DPAPI. --> <value>AQ...g==</value> </encryptedKey> </encryptedSecret> </descriptor> </descriptor> </key>
  15. 19 @leastprivilege Claims Transformation • Per-request manipulation of principal &

    claims app.UseClaimsTransformation(context => { if (context.Principal.Identity.IsAuthenticated) { CreateApplicationPrincipal(context); } return Task.FromResult(context.Principal); });
  16. 20 @leastprivilege External Authentication • In the box – Google,

    Twitter, Facebook, Microsoft Account – OpenID Connect & JSON Web Tokens • New generic OAuth 2.0 middleware makes on-boarding other proprietary providers easier – LinkedIn, Slack, Spotify, WordPress, Yahoo, Github, Instragram, BattleNet, Dropbox, Paypal, Vimeo… https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
  17. 21 @leastprivilege Social Identity Providers • Enabled with UseGoogleAuthentication, et

    al. – Rely upon cookie authentication middleware app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = "Cookies", AutomaticAuthenticate = true, }); app.UseGoogleAuthentication(new GoogleOptions { AuthenticationScheme = "Google", SignInScheme = "Cookies", ClientId = "998042782978...", ClientSecret = "HsnwJri_53zn7..." });
  18. 22 @leastprivilege Social Identity Providers • ChallengeAsync triggers redirect for

    login – Control URL user returns to with AuthenticationProperties – MVC ChallengeResult works with action result architecture var props = new AuthenticationProperties { RedirectUri = "/Home/Secure" }; await HttpContext.Authentication.ChallengeAsync("Google", props); // or if using MVC: return new ChallengeResult("Google", props);
  19. 23 @leastprivilege Mixing local and external Authentication • Typically need

    registration logic for users from social providers – Use additional cookie middleware for processing registration app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = "Temp", AutomaticAuthenticate = false, AutomaticChallenge = false }); app.UseGoogleAuthentication(new GoogleOptions { AuthenticationScheme = "Google", SignInScheme = "Temp", ClientId = "998042782978...", ClientSecret = "HsnwJri_53zn7..." });
  20. 24 @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.Authentication.AuthenticateAsync("Temp"); 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.Authentication.SignInAsync("Cookies", user); await HttpContext.Authentication.SignOutAsync("Temp");
  21. 25 @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…
  22. 26 @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
  23. 31 @leastprivilege Authentication for Web Applications GET /authorize ?client_id=app1 &redirect_uri=https://app.com/cb

    &response_type=id_token &response_mode=form_post &nonce=j1y…a23 &scope=openid profile email
  24. 35 @leastprivilege Identity Token { "typ": "JWT", "alg": "RS256", "kid":

    "mj399j…" } { "iss": "https://idsrv3", "exp": 1340819380, "aud": "app1", "nonce": "j1y…a23", "sub": "182jmm199", "email": "[email protected]", "name": "Alice", "amr": [ "password" ], "auth_time": 12340819300 } Header Payload eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMD.4MTkzODAsDQogImh0dHA6Ly9leGFt Header Payload Signature
  25. 36 @leastprivilege OpenID Connect Middleware • Much improved – support

    for implicit, code and hybrid flow – support for userinfo endpoint & better token management app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions { AuthenticationScheme = "OIDC", SignInScheme = "Cookies", Authority = "https://demo.identityserver.io", ClientId = "mvc", ClientSecret = "secret" ResponseType = "code id_token", SaveTokens = true });
  26. 37 @leastprivilege Web API Authentication • Middleware for JWT access

    tokens built-in – cookies not recommended app.UseJwtBearerAuthentication(new JwtBearerOptions { Authority = "https://localhost:44300", Audience = "my.api", options.AutomaticAuthenticate = true; });
  27. 38 @leastprivilege Issuing Tokens • No built-in token issuance middleware

    anymore – "Azure B2C Emulator" soon • IdentityServer is a full featured & certified token service – OpenID Connect and OAuth 2.0 (+ related specifications) http://github.com/identityserver
  28. 39 @leastprivilege Authorization • Complete re-write – support for unauthorized

    vs forbidden – better separation of business code and authorization logic – re-usable policies – resource/action based authorization – DI enabled
  29. 40 @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); } } * …and who thought that would be a good idea?
  30. 41 @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
  31. 42 @leastprivilege Programmatically using policies public class CustomerController : Controller

    { private readonly IAuthorizationService _authz; public CustomerController(IAuthorizationService authz) { _authz = authz; } public async Task<IActionResult> Manage() { var allowed = await _authz.AuthorizeAsync(User, "ManageCustomers"); if (!allowed) return Challenge(); return View(); } }
  32. 43 @leastprivilege …or from a View @using Microsoft.AspNetCore.Authorization @inject IAuthorizationService

    _authz @if (await _authz.AuthorizeAsync(User, "ManageCustomers")) { <div> <a href="/customers/test">Manage</a> </div> }
  33. 44 @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; } }
  34. 45 @leastprivilege Handling Requirements 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); } } }
  35. 46 @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
  36. 47 @leastprivilege Example: Document resource public class DocumentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement,

    Document> { public override Task HandleRequirementAsync( AuthorizationHandlerContext context, OperationAuthorizationRequirement operation, Document resource) { // authorization logic } } services.AddTransient<IAuthorizationHandler, DocumentAuthorizationHandler>(); Add handler in DI:
  37. 48 @leastprivilege 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)) { // forbidden return Challenge(); } // do stuff } }
  38. 49 @leastprivilege Resources • https://github.com/leastprivilege/ – AspNetCoreSecuritySamples • https://github.com/dotnet –

    corefx – coreclr • https://github.com/aspnet – home – security – announcements • http://docs.asp.net