2017-08-16 88 views
2

我正在使用ASP.NET MVC 5.我寫了一個小的過濾器屬性,用於將內容安全策略添加到響應標題。下面是代碼:內容安全策略屬性Mvc - 添加多次

public class ContentSecurityPolicyFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     HttpResponseBase response = filterContext.HttpContext.Response; 

     response.AddHeader("Content-Security-Policy", "default-src *; " + 
      "img-src * data:; " + 
      "style-src 'self' 'unsafe-inline' http://fonts.googleapis.com https://fonts.googleapis.com; " + 
      "script-src 'self' 'unsafe-inline' 'unsafe-eval' " + 

      "localhost:*/* " + 

      "https://facebook.com " + 
      "*.facebook.com " + 

      "https://facebook.net " + 
      "*.facebook.net " + 

      "https://onesignal.com " + 
      "*.onesignal.com " + 

      "https://abtasty.com *.abtasty.com *.convertexperiments.com " + 

      "http://www.googletagmanager.com " + 
      "https://www.googletagmanager.com " + 

      "http://www.google-analytics.com " + 
      "https://www.google-analytics.com " + 

      "http://www.googleadservices.com " + 
      "https://www.googleadservices.com "); 

     base.OnActionExecuting(filterContext); 
    } 
} 

要一個FilterConfig:

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     //... 
     filters.Add(new ContentSecurityPolicyFilterAttribute()); 
    } 
} 

我的問題是,這個代碼添加多個Content-Security-Policy頭在每次請求。它應該運行一次,並且只添加一次這個頭文件。我對嗎?

CSP Header Added Too Many Times

所以我能解決這個問題?

+0

您是否嘗試過在'OnResultExecuting'中添加標頭,而不是停止重定向或許重複? –

+0

@RyanSearle感謝您的想法。但我採取了相同的結果(過濾器被稱爲多次,並添加內容安全策略多個...) –

回答

2

要解決此問題,您需要發現爲什麼您的過濾器被多次調用(假設它是!),我找到了它發生的一種方式,但它可能不一樣(將調試器附加到過濾器的第一行,並查看調用堆棧以查看觸發它的是什麼)。

我在人少的MVC項目中使用下列減少的情況下(具有默認HomeController和CO),以驗證在最簡單的情況下,ContentSecurityPolicyFilterAttribute過濾器僅被執行一次:

// Truncated CSP filter 
public class ContentSecurityPolicyFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     HttpResponseBase response = filterContext.HttpContext.Response; 

     response.AddHeader("Content-Security-Policy", "default-src *; img-src * data:; "); 

     base.OnActionExecuting(filterContext); 
    } 
} 

// Addition to FilterConfig.cs 
filters.Add(new ContentSecurityPolicyFilterAttribute()); 

通過上面的代碼中,我只看到Content-Security-Policy頭本的一個實例,即使在HomeControllerIndex動作更改爲:

return RedirectToAction("Contact"); 

兩個請求抄w(使用Fiddler),請求Index返回HTTP 302重定向到/Home/Contact,並且兩者都只包含一個CSP頭。

如何獲得一個以上的Content-Security-Policy

Partial Views

如果您使用的是部分視圖,那麼這可能是重複頭部的原因,特別是如果他們調用Controller動作來填充它們自己。

通過添加以下代碼的HomeController:

public ActionResult PartialContentForHome() 
{ 
    return View("PartialContentForHome"); 
} 

創建下視圖\共享稱爲PartialContentForHome.cshtml包含(正被調用的局部視圖視覺證明)以下標記了一個新的局部視圖:

@{ 
    Layout = null; 
} 
<h1> 
    Partial! 
</h1> 

最後,加入@Html.Action("PartialContentForHome", "Home")到視圖文件Views\Home\Index.cshtml,您:

  1. 獲取由Views\Home\Index.cshtmlViews\Shared\PartialContentForHome.cshtml組成的頁面,即文本「部分!「將在頁面中顯示
  2. 將達到一個已經設置在CSP濾波器的第一線斷點兩次
  3. 會看到發送到客戶端
  4. 響應的CSP頭的兩個實例

如何避免如果問題是由局部視圖引起/調用控制器動作有一個以上的頭

,你需要確保該過濾器對其自身進行調節,以每個請求只執行一次。一種方法d Ø這將是東西值到HttpContext.Items集合作爲一個「我已經附加了頭」標記,例如使用:

public class ContentSecurityPolicyFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if (!filterContext.RequestContext.HttpContext.Items.Contains(nameof(ContentSecurityPolicyFilterAttribute))) 
     { 
      HttpResponseBase response = filterContext.HttpContext.Response; 

      response.AddHeader("Content-Security-Policy", "default-src *; img-src * data:; "); 
      filterContext.RequestContext.HttpContext.Items.Add(nameof(ContentSecurityPolicyFilterAttribute), string.Empty); 
     } 
     base.OnActionExecuting(filterContext); 
    } 
} 

在過濾器中,這個更新的版本,只要它執行它看起來在HttpContext.Items中爲自己命名的條目。如果不存在,它將添加標題,然後將條目添加到HttpContext.Items,以便如果再次運行,Content-Security-Policy標題不會被重新添加。這將在一般情況下工作,以確保每個請求一旦超過一個過濾器,不執行以上,但我們可以去一個更好的標題,具體如下:

public class ContentSecurityPolicyFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     HttpResponseBase response = filterContext.HttpContext.Response; 
     var header = response.Headers["Content-Security-Policy"]; 
     if (header == null) 
     { 
      response.AddHeader("Content-Security-Policy", "default-src *; img-src * data:; "); 
     } 
     base.OnActionExecuting(filterContext); 
    } 
} 

即所有我們需要做的是檢查查看頭部是否在響應的Headers集合中,如果是,則不要再次添加它。

+0

這些提示幫助了我很多。這就是爲什麼我喜歡答案。無論如何,我檢查partials,他們沒有「Layout = null;」所以我加了他們。但結果是一樣的。另外,當我把一個調試點,我看到請求來自不同的控制器。如HomeController,NopCommerce的CatalogController(用於網站菜單),NopCommerce的WidgetController等。我不知道該怎麼做。我可以將CSP添加到僅web.config,但我不想更改配置。因爲webconfig已經有太多的行了。凌亂......也許我需要一種不同的方法。 –

+1

@Lost_In_Library,我不認爲* Layout = null會對過濾器是否被執行產生任何影響,你的「問題」是你註冊了一個過濾器,它將在* all *動作上執行,但每個請求都有多個動作執行。我對解決方案/解決方法有一些想法,我將在一兩分鐘內添加到答案中=) – Rob

+0

對不起,感謝您的回覆,我正在檢查... –