securing)web)applica0ons)and)apis)...
TRANSCRIPT
Securing Web Applica0ons and APIs with .NET & ASP.NET
today and tomorrow
Dominick Baier hCp://leastprivilege.com @leastprivilege
2 @leastprivilege
Dominick Baier • Independent Consultant
– Specializing on Iden9ty & Access Control – Working with SoAware Development Teams (ISVs and in-‐house)
• Creator and Maintainer of Iden0tyServer OSS Project – OpenID Connect & OAuth 2.0 Implementa9on on OWIN – hLp://iden9tyserver.io
• MicrosoM MVP for Developer Security • .NET Founda0on Advisory Board • [email protected] • hCp://leastprivilege.com
3 @leastprivilege
Where are we?
ASP.NET =< 4.5 ASP.NET 4.5 ASP.NET 5
System.Web.dll Modules & Handlers ASP.NET WebForms ASP.NET MVC ASP.NET Web API ASP.NET SignalR (Simple) Membership
6 @leastprivilege
Mo9va9on • System.Web.dll (aka ASP.NET)
– 12+ year old web framework – Unnamed MicrosoA employee on System.Web:
• “We fix one bug and open seven new ones” – Always executes lots of WebForms-‐specific code
hCps://twiCer.com/aeinbu/status/407816285058514944
7 @leastprivilege
Where are we?
ASP.NET =< 4.5 ASP.NET 4.5 ASP.NET 5
"System.Web.dll" Modules & Handlers ASP.NET WebForms ASP.NET MVC (Simple) Membership
"System.Web.dll" Modules & Handlers ASP.NET WebForms ASP.NET MVC OWIN & Katana ASP.NET Web API ASP.NET SignalR ASP.NET Iden9ty 1/2
9 @leastprivilege
OWIN Specifica9on
• Environment models HTTP request/response – IDic%onary<string, object>
• All .NET primi9ves so no framework dependencies – Standard set of key/value pairs
Key Type
owin.RequestScheme string
owin.RequestMethod string
owin.RequestPath string
owin.RequestBody Stream
owin.RequestHeaders IDic9onary<string, string[]>
owin.ResponseStatusCode int
owin.ResponseHeaders IDic9onary<string, string[]>
owin.ResponseBody Stream
10 @leastprivilege
Middleware
Middleware
Func<IDictionary<string, object>>, Task>
Func<IDictionary<string, object>>, Task> using AppFunc =
using MidFunc = Func<AppFunc, AppFunc>;
11 @leastprivilege
Middleware Architecture
• Middleware are linked components that process requests • Applica0on code targe0ng a framework (e.g. Web API)
Host
OWIN Server
Some Middleware
Some Other Middleware User Agent Applica9on
13 @leastprivilege
Where are we?
ASP.NET =< 4.5 ASP.NET 4.5 ASP.NET 5
"System.Web.dll" Modules & Handlers ASP.NET WebForms ASP.NET MVC (Simple) Membership
"System.Web.dll" Modules & Handlers ASP.NET WebForms ASP.NET MVC OWIN & Katana ASP.NET Web API ASP.NET SignalR ASP.NET Iden9ty 1/2
"Desktop" CLR & Core CLR MVC 6 SignalR 3 ASP.NET Iden9ty 3
14 @leastprivilege
ASP.NET 5 Architecture
• ASP.NET 5 is the run0me – can host OWIN and "na9ve" middleware
• MVC 6 is MicrosoM's applica0on framework – is OWIN compa9ble
Host
OWIN Server
OWIN Middleware
ASP.NET 5 Middleware User Agent MVC 6
15 @leastprivilege
Security in the new Architecture
• Everything is based on claims • Authen0ca0on is implemented as middleware – cookies – external authen9ca9on
• social providers (Google, Facebook etc…) • integra9on providers (WS-‐Federa9on) • modern applica9ons (OpenID Connect)
• Other security related middleware – CORS – Audi9ng
16 @leastprivilege
Authen9ca9on Manager
• Katana introduces uniform authen0ca0on API
public interface IAuthenticationManager { ClaimsPrincipal User { get; set; } void SignIn(params ClaimsIdentity[] identities); void SignOut(params string[] authenticationTypes); Task<AuthenticateResult> AuthenticateAsync(string authenticationType); void Challenge(params string[] authenticationTypes); IEnumerable<AuthenticationDescription> GetAuthenticationTypes(); }
17 @leastprivilege
Cookie Middleware
• Forms Authen0ca0on replacement
public void Configuration(IAppBuilder app) { var options = new CookieAuthenticationOptions { AuthenticationType = "Cookies", LoginPath = new PathString("/account/login"), ExpireTimeSpan = TimeSpan.FromHours(4), CookieSecure = CookieSecureOption.Always }; app.UseCookieAuthentication(options); }
18 @leastprivilege
External Authen9ca9on Name Descrip0on
Google OAuth2
TwiLer OAuth1
Facebook OAuth2
MicrosoA Account OAuth2
JWT Bearer (JSON web token)
(Azure) Ac9ve Directory Bearer (JSON web tokens)
Federa9on WS-‐Federa9on
OIDC OpenID Connect
Yahook, LinkedIn, Steam, GitHub, Instagram, StackExchange, BaLle.Net, Asana, HealthGraph, SalesForce (hLps://github.com/owin-‐middleware/OwinOAuthProviders)
hLp://www.oauthforaspnet.com/
19 @leastprivilege
The big Picture
Browser Web App
Security Token Service
Google, Facebook etc… Enterprise Authen0ca0on Federa0on Registra0on / Account linking
WS-‐Federa0on OpenID Connect + Cookies
1
2
21 @leastprivilege
Authen9ca9on/Access Tokens in Nutshell
GET /authorize ?client_id=app1 &redirect_uri=hCps://<callback> &response_type=id_token token &scope=openid email api1 api2
26 @leastprivilege
Target Architecture
Browser
Na0ve App
Server App
Web App
Web API Web API
Web API
Security Token Service
27 @leastprivilege
Security Protocols
Browser
Na0ve App
Server App
Web App
Web API Web API
Web API
OpenID Connect
OAuth2
OAuth2
OAuth2
OAuth2
OAuth2
OAuth2
Security Token Service
29 @leastprivilege
ClaimsPrincipal & the new Authen9ca9on APIs
• Users are now ClaimsPrincipals – H6pContext.User, Controller.User
• H.pResponse.SignIn/SignOut – Sign in/out a user
• HCpResponse.Challenge – Ini9ate challenge (also new ChallengeResult)
• H.pContext.Authen=cate – Authen9cate using a specific scheme
• H.pContext.GetAuthen=ca=onSchemes – Get available authen9ca9on schemes
30 @leastprivilege
Authen9ca9on Middleware
• Authen0ca0on implemented as middleware
• By ASP.NET Team – Cookies – Google, MicrosoA Account, TwiLer, Facebook – OAuth2 Bearer Tokens
• By Azure AD Team – OpenID Connect – WS-‐Federa9on
31 @leastprivilege
Cookie Authen9ca9on
app.UseCookieAuthentication(options => { options.LoginPath = new PathString("/account/login"); options.AutomaticAuthentication = true; options.AuthenticationScheme = "Cookies"; });
if (IsValid(username, password)) { var principal = CreatePrincipal(username); Response.SignIn("Cookies", principal); }
Startup
Account controller
32 @leastprivilege
Data Protec9on
• Cookies (amongst other things) need protec0on – <machineKey /> in previous versions
• New DataProtec0on API is much more powerful and flexible – No more secrets in configura9on file – Automa9c key roll over and protec9on – But needs some planning ahead
• hCp://docs.asp.net/en/latest/security/data-‐protec0on/index.html
33 @leastprivilege
Default Key Container Loca9ons
• On Azure Web Apps (no encryp0on) – %HOME%\ASP.NET\DataProtec9on-‐Keys
• If user profile is loaded (encrypted) – %LOCALAPPDATA%\ASP.NET\DataProtec9on-‐Keys
• IIS / no profile (encrypted) – Registry HKLM
• In-‐Memory • Manual configura0on
<?xml version="1.0" encoding="uw-‐8"?> <key id="eacc6495-‐83a3-‐4aaf-‐ad29-‐fee164c69963" version="1"> <crea9onDate>2015-‐05-‐02T08:20:38.6577127Z</crea9onDate> <ac9va9onDate>2015-‐05-‐02T08:20:38.6424674Z</ac9va9onDate> <expira9onDate>2015-‐07-‐31T08:20:38.6424674Z</expira9onDate> <descriptor> <descriptor> <encryp9on algorithm="AES_256_CBC" /> <valida9on algorithm="HMACSHA256" /> <encryptedSecret> <encryptedKey xmlns=""> <!-‐-‐ This key is encrypted with Windows DPAPI. -‐-‐> <value>AQ...g==</value> </encryptedKey> </encryptedSecret> </descriptor> </descriptor> </key>
34 @leastprivilege
External Authen9ca9on
• Invoke with H.pResponse.Challenge or ChallengeResult
app.UseCookieAuthentication(options => { options.LoginPath = new PathString("/account/login"); options.AutomaticAuthentication = true; options.AuthenticationScheme = "Cookies"; }); app.UseGoogleAuthentication(options => { options.ClientId = "434…48"; options.ClientSecret = "3gc…6PWo"; options.AuthenticationScheme = "Google"; options.SignInScheme = "Cookies"; });
35 @leastprivilege
OAuth2 Bearer Tokens
• Expects JSON Web Token (JWT) • Supports OpenID Connect Discovery Document
app.UseOAuthBearerAuthentication(options => { options.Authority = "https://identityserver.io"; options.Audience = "https://identityserver.io/resources"; options.AutomaticAuthentication = true; });
36 @leastprivilege
Authoriza9on
• Complete re-‐write – Separa9on of controller/business code and authoriza9on policy
– Re-‐usable policies – DI enabled – Claims-‐aware
• S0ll in flux
37 @leastprivilege
[Authorize]
• General concept stays the same [Authorize]
public class HomeController : Controller { [AllowAnonymous] public IActionResult Index() { return View(); } [Authorize(Roles = "Sales")] public IActionResult About() { return View(User); } }
38 @leastprivilege
Authoriza9on policies
services.ConfigureAuthorization(options => { options.AddPolicy("BlueTeamIntern", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("team", "blue"); policy.RequireClaim("status", "intern"); }); };
[Authorize("BlueTeamIntern")] public IActionResult Blue() { // stuff }
Startup
Controller
39 @leastprivilege
Custom Requirements public class TeamRequirement : AuthorizationHandler<TeamRequirement>, IAuthorizationRequirement { private readonly string _status; private readonly string _team; public TeamRequirement(string team, string status) { _team = team; _status = status; } public override void Handle( AuthorizationContext context, TeamRequirement requirement) { if (context.User.HasClaim("team", _team) && context.User.HasClaim("status", _status)) { context.Succeed(requirement); } } }
40 @leastprivilege
Resource-‐based Authoriza9on
public class GameAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Game> { private readonly IPermissionStore _permissions; public GameAuthorizationHandler(IPermissionStore permissions) { _permissions = permissions; } public override void Handle( AuthorizationContext context, OperationAuthorizationRequirement requirement, Game resource) { // custom logic } }
41 @leastprivilege
Registering the authoriza9on handler
• In RegisterServices
services.AddScoped<IPermissionStore, PermissionStore>(); services.AddTransient<IAuthorizationHandler, GameAuthorizationHandler>();
42 @leastprivilege
Invoking the authoriza9on handler public class GameController : Controller { private readonly IAuthorizationService _authz; public GameController(IAuthorizationService authz) { _authz = authz; } public IActionResult Start() { var game = new Game { Location = "DataCenterEast", Type = "Virus" }; if (_authz.Authorize(User, game, GameOperations.Attack)) { return Content("Attack has started..."); } return HttpUnauthorized(); } }