extremecold 2019-09-07
å容å®å¨çç¥ï¼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/");
   });å¯å¨åç°ï¼è§å¯ç½ç»èµæºãæµè§å¨å·²ç»å许æ¬å°åè¿ç¨èµæºã

æ»ç»
以ä¸å°±æ¯è¿ç¯æç« çå¨é¨å容äºï¼å¸ææ¬æçå容对大家çå¦ä¹ æèå·¥ä½å·æä¸å®çåèå¦ä¹ ä»·å¼ï¼è°¢è°¢å¤§å®¶å¯¹èæ¬ä¹å®¶çæ¯æã