ASP.NET Core中如何利用Csp标头对抗Xss攻击
å容å®å¨çç¥ï¼CSPï¼æ¯ä¸ä¸ªå¢å çå®å¨å±ï¼å¯å¸®å©æ£æµåç¼è§£æäºç±»åçæ»å»ï¼åæ¬è·¨ç«ç¹èæ¬ï¼XSSï¼åæ°æ®æ³¨å¥æ»å»ãè¿äºæ»å»ç¨äºä»æ°æ®çªåå°ç«ç¹ç ´åææ¶æ软件ååçææå容ï¼æ·±å¥CSPï¼
ç®èè¨ä¹ï¼CSPæ¯ç½é¡µæ§å¶å许å è½½åªäºèµæºçä¸ç§æ¹å¼ãä¾å¦ï¼é¡µé¢å¯ä»¥æ¾å¼å£°æå许ä»ä¸å è½½JavaScriptï¼CSSåå¾åèµæºãè¿æå©äºé²æ¢è·¨ç«ç¹èæ¬ï¼XSSï¼æ»å»çé®é¢ã
å®ä¹å¯ç¨äºéå¶åè®®ï¼ä¾å¦éå¶éè¿HTTPSå è½½çå容ãCSPéè¿ Content-Security-Policy HTTPååºä¸çæ 头å®ç°ã
å¯ç¨CSP,æ¨éè¦éç½®Webæå¡å¨ä»¥è¿åContent-Security-Policy HTTPæ 头ãé£ä¹å¨è¿ç¯æç« ä¸ï¼æ们å°è¦å°è¯å°CSPæ·»å å°ASP.NET Coreåºç¨ç¨åºä¸ã
app.Use(async (ctx, next) => { ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; report-uri /cspreport"); await next(); });
å¨Home/Indexä¸å¼å¥cdnæ件ï¼ç¶åæ们å¯å¨é¡¹ç®ï¼ççä¼åçä»ä¹ï¼
è¿è¡å¹¶è§å¯é误ãå 载页é¢æ¶ï¼æµè§å¨æç»ä»è¿ç¨æºå è½½ã
æ以æ们å¯ä»¥ç»ç»CSPæ¥æ§å¶æ们çç½ååï¼å¨éç½®å½ä¸éè¦å¡«åæ¥æºä»¥åå容ï¼ä»¥ä¸æ¯å¸¸ç¨éå¶çé项ã
æ¥æºï¼
*: å许任ä½ç½åã
âself': å许ææä¾é¡µé¢çæ¥æºã请注æï¼åå¼å·æ¯å¿éçã
ânone': ä¸å许任ä½æ¥æºã请注æï¼åå¼å·æ¯å¿éçã
Host: å许æå®çäºèç½ä¸»æºï¼æå称æIPå°åï¼ãéé符ï¼æå·å符ï¼å¯ç¨äºåæ¬ææååï¼ä¾å¦httpï¼//*.foo.com
âunsafe-line': å许åèèæ¬
ânonce-[base64-value]': å许å·æç¹å®nonceçåèèæ¬ï¼ä½¿ç¨ä¸æ¬¡çæ°åï¼ã对äºæ¯ä¸ªHTTP请æ±/ååºï¼åºè¯¥å¯¹nonceè¿è¡å å¯åå¯ä¸ã
æ令ï¼
script-srcï¼å®ä¹ææçJavaScriptæº
style-srcï¼å®ä¹æ ·å¼è¡¨çæææ¥æº
img-srcï¼å®ä¹ææçå¾åæº
connect-srcï¼å®ä¹å¯ä»¥è¿è¡AJAXè°ç¨çæææº
font-srcï¼å®ä¹ææçåä½æ¥æº
object-srcï¼å®ä¹<object>ï¼<embed>å<applet>åç´ çæææº
media-srcï¼å®ä¹ææçé³é¢åè§é¢æº
form-actionï¼å®ä¹å¯ç¨ä½HTML <form>æä½çæææºã
default-srcï¼æå®å è½½å容çé»è®¤çç¥
æ们å¯ä»¥å¨å¯éç¨çä¸é´ä»¶ä¸å°è£æ建åæ·»å CSP头ã以ä¸æ¯ä¸ä¸ªè®©æ¨å¥é¨ç示ä¾ãä½ å¯ä»¥æ ¹æ®éè¦æ©å±å®ãé¦åï¼å建ä¸ä¸ªç¨äºä¿åæºçç±»ã
public class CspOptions { public List<string> Defaults { get; set; } = new List<string>(); public List<string> Scripts { get; set; } = new List<string>(); public List<string> Styles { get; set; } = new List<string>(); public List<string> Images { get; set; } = new List<string>(); public List<string> Fonts { get; set; } = new List<string>(); public List<string> Media { get; set; } = new List<string>(); }
å¼åä¸ä¸ªä¸é´ä»¶ä¸å®æ¯éè¦ä¸ä¸ªæé å¨çï¼è¿å°ç¨äº.net core ç注å¥å°è¿è¡ç¯å¢ä¸ã
public sealed class CspOptionsBuilder { private readonly CspOptions options = new CspOptions(); internal CspOptionsBuilder() { } public CspDirectiveBuilder Defaults { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Scripts { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Styles { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Images { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Fonts { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Media { get; set; } = new CspDirectiveBuilder(); internal CspOptions Build() { this.options.Defaults = this.Defaults.Sources; this.options.Scripts = this.Scripts.Sources; this.options.Styles = this.Styles.Sources; this.options.Images = this.Images.Sources; this.options.Fonts = this.Fonts.Sources; this.options.Media = this.Media.Sources; return this.options; } } public sealed class CspDirectiveBuilder { internal CspDirectiveBuilder() { } internal List<string> Sources { get; set; } = new List<string>(); public CspDirectiveBuilder AllowSelf() => Allow("'self'"); public CspDirectiveBuilder AllowNone() => Allow("none"); public CspDirectiveBuilder AllowAny() => Allow("*"); public CspDirectiveBuilder Allow(string source) { this.Sources.Add(source); return this; } }
好äºï¼æ们å建ä¸ä¸ªä¸é´ä»¶ã
namespace XSSDefenses.XSSDefenses.MiddlerWare { public sealed class CspOptionMiddlerWare { private const string HEADER = "Content-Security-Policy"; private readonly RequestDelegate next; private readonly CspOptions options; public CspOptionMiddlerWare( RequestDelegate next, CspOptions options) { this.next = next; this.options = options; } public async Task Invoke(HttpContext context) { context.Response.Headers.Add(HEADER, GetHeaderValue()); await this.next(context); } private string GetHeaderValue() { var value = ""; value += GetDirective("default-src", this.options.Defaults); value += GetDirective("script-src", this.options.Scripts); value += GetDirective("style-src", this.options.Styles); value += GetDirective("img-src", this.options.Images); value += GetDirective("font-src", this.options.Fonts); value += GetDirective("media-src", this.options.Media); return value; } private string GetDirective(string directive, List<string> sources) => sources.Count > 0 ? $"{directive} {string.Join(" ", sources)}; " : ""; } }
以å设置å®çæ©å±æ¹æ³ã
namespace XSSDefenses.XSSDefenses.Extensions { public static class CspMiddlewareExtensions { public static IApplicationBuilder UseCsp( this IApplicationBuilder app, Action<CspOptionsBuilder> builder) { var newBuilder = new CspOptionsBuilder(); builder(newBuilder); var options = newBuilder.Build(); return app.UseMiddleware<CspOptionMiddlerWare>(options); } } }
æ们ç°å¨å¯ä»¥å¨Startupç±»ä¸éç½®ä¸é´ä»¶ã
app.UseCsp(builder => { builder.Styles.AllowSelf() .Allow(@"https://ajax.aspnetcdn.com/"); });
å¯å¨åç°ï¼è§å¯ç½ç»èµæºãæµè§å¨å·²ç»å许æ¬å°åè¿ç¨èµæºã
æ»ç»
以ä¸å°±æ¯è¿ç¯æç« çå¨é¨å容äºï¼å¸ææ¬æçå容对大家çå¦ä¹ æèå·¥ä½å·æä¸å®çåèå¦ä¹ ä»·å¼ï¼è°¢è°¢å¤§å®¶å¯¹èæ¬ä¹å®¶çæ¯æã