Unset X-Frame-Options header correctly (#4721)

* Unset X-Frame-Options header correctly

According to the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) there are onlye the `DENY` and `SAMEORIGIN` options, `ALLOW-FROM` being deprecated. Hence we have to actively unset the header, as we made `DENY` the default.

This also unsets the X-Frame-Options header for the public form pages, which fixes #4666.

* Ignore anti forgery token in Forms

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
This commit is contained in:
d11n
2023-03-01 07:27:18 +01:00
committed by GitHub
parent 5790bed766
commit 23761eacc1
7 changed files with 25 additions and 27 deletions

View File

@@ -208,6 +208,7 @@ namespace BTCPayServer.Controllers
[HttpGet("{payReqId}/form")] [HttpGet("{payReqId}/form")]
[HttpPost("{payReqId}/form")] [HttpPost("{payReqId}/form")]
[AllowAnonymous] [AllowAnonymous]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> ViewPaymentRequestForm(string payReqId, FormViewModel viewModel) public async Task<IActionResult> ViewPaymentRequestForm(string payReqId, FormViewModel viewModel)
{ {
var result = await _PaymentRequestRepository.FindPaymentRequest(payReqId, GetUserId()); var result = await _PaymentRequestRepository.FindPaymentRequest(payReqId, GetUserId());

View File

@@ -30,7 +30,7 @@ namespace BTCPayServer.Controllers
} }
[HttpGet] [HttpGet]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> ShowLightningNodeInfo(string storeId, string cryptoCode) public async Task<IActionResult> ShowLightningNodeInfo(string storeId, string cryptoCode)
{ {
var store = await _StoreRepository.FindStore(storeId); var store = await _StoreRepository.FindStore(storeId);

View File

@@ -10,28 +10,18 @@ namespace BTCPayServer.Filters
Value = value; Value = value;
} }
public XFrameOptionsAttribute(XFrameOptions type, string allowFrom = null) public XFrameOptionsAttribute(XFrameOptions type)
{ {
switch (type) Value = type switch
{ {
case XFrameOptions.Deny: XFrameOptions.Deny => "DENY",
Value = "deny"; XFrameOptions.SameOrigin => "SAMEORIGIN",
break; XFrameOptions.Unset => null,
case XFrameOptions.SameOrigin: _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
Value = "deny"; };
break;
case XFrameOptions.AllowFrom:
Value = $"allow-from {allowFrom}";
break;
case XFrameOptions.AllowAll:
Value = "allow-all";
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
} }
public string Value { get; set; } private string Value { get; set; }
public void OnActionExecuted(ActionExecutedContext context) public void OnActionExecuted(ActionExecutedContext context)
{ {
@@ -39,7 +29,7 @@ namespace BTCPayServer.Filters
public void OnActionExecuting(ActionExecutingContext context) public void OnActionExecuting(ActionExecutingContext context)
{ {
if (context.IsEffectivePolicy<XFrameOptionsAttribute>(this)) if (context.IsEffectivePolicy(this))
{ {
context.HttpContext.Response.SetHeaderOnStarting("X-Frame-Options", Value); context.HttpContext.Response.SetHeaderOnStarting("X-Frame-Options", Value);
} }
@@ -49,8 +39,7 @@ namespace BTCPayServer.Filters
{ {
Deny, Deny,
SameOrigin, SameOrigin,
AllowFrom, Unset
AllowAll
} }
} }
} }

View File

@@ -11,6 +11,7 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Filters;
using BTCPayServer.Forms.Models; using BTCPayServer.Forms.Models;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@@ -129,6 +130,7 @@ public class UIFormsController : Controller
[AllowAnonymous] [AllowAnonymous]
[HttpGet("~/forms/{formId}")] [HttpGet("~/forms/{formId}")]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> ViewPublicForm(string? formId) public async Task<IActionResult> ViewPublicForm(string? formId)
{ {
FormData? formData = await _formDataService.GetForm(formId); FormData? formData = await _formDataService.GetForm(formId);
@@ -166,6 +168,7 @@ public class UIFormsController : Controller
[AllowAnonymous] [AllowAnonymous]
[HttpPost("~/forms/{formId}")] [HttpPost("~/forms/{formId}")]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> SubmitForm(string formId, public async Task<IActionResult> SubmitForm(string formId,
[FromServices] StoreRepository storeRepository, [FromServices] StoreRepository storeRepository,
[FromServices] UIInvoiceController invoiceController) [FromServices] UIInvoiceController invoiceController)

View File

@@ -117,7 +117,7 @@ namespace BTCPayServer.Hosting
services.AddSingleton<LightningAddressService>(); services.AddSingleton<LightningAddressService>();
var mvcBuilder = services.AddMvc(o => var mvcBuilder = services.AddMvc(o =>
{ {
o.Filters.Add(new XFrameOptionsAttribute("DENY")); o.Filters.Add(new XFrameOptionsAttribute(XFrameOptionsAttribute.XFrameOptions.Deny));
o.Filters.Add(new XContentTypeOptionsAttribute("nosniff")); o.Filters.Add(new XContentTypeOptionsAttribute("nosniff"));
o.Filters.Add(new XXSSProtectionAttribute()); o.Filters.Add(new XXSSProtectionAttribute());
o.Filters.Add(new ReferrerPolicyAttribute("same-origin")); o.Filters.Add(new ReferrerPolicyAttribute("same-origin"));

View File

@@ -54,7 +54,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
[HttpGet("/")] [HttpGet("/")]
[HttpGet("/apps/{appId}/crowdfund")] [HttpGet("/apps/{appId}/crowdfund")]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
[DomainMappingConstraint(AppType.Crowdfund)] [DomainMappingConstraint(AppType.Crowdfund)]
public async Task<IActionResult> ViewCrowdfund(string appId, string statusMessage) public async Task<IActionResult> ViewCrowdfund(string appId, string statusMessage)
{ {
@@ -86,7 +86,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
[HttpPost("/")] [HttpPost("/")]
[HttpPost("/apps/{appId}/crowdfund")] [HttpPost("/apps/{appId}/crowdfund")]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.AllowAll)] [XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
[IgnoreAntiforgeryToken] [IgnoreAntiforgeryToken]
[EnableCors(CorsPolicies.All)] [EnableCors(CorsPolicies.All)]
[DomainMappingConstraint(AppType.Crowdfund)] [DomainMappingConstraint(AppType.Crowdfund)]

View File

@@ -62,9 +62,10 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
public FormDataService FormDataService { get; } public FormDataService FormDataService { get; }
[HttpGet("/")] [HttpGet("/")]
[HttpGet("/apps/{appId}/pos")]
[HttpGet("/apps/{appId}/pos/{viewType?}")] [HttpGet("/apps/{appId}/pos/{viewType?}")]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
[DomainMappingConstraint(AppType.PointOfSale)] [DomainMappingConstraint(AppType.PointOfSale)]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> ViewPointOfSale(string appId, PosViewType? viewType = null) public async Task<IActionResult> ViewPointOfSale(string appId, PosViewType? viewType = null)
{ {
var app = await _appService.GetApp(appId, AppType.PointOfSale); var app = await _appService.GetApp(appId, AppType.PointOfSale);
@@ -118,11 +119,11 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
[HttpPost("/")] [HttpPost("/")]
[HttpPost("/apps/{appId}/pos/{viewType?}")] [HttpPost("/apps/{appId}/pos/{viewType?}")]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.AllowAll)]
[IgnoreAntiforgeryToken] [IgnoreAntiforgeryToken]
[EnableCors(CorsPolicies.All)] [EnableCors(CorsPolicies.All)]
[DomainMappingConstraint(AppType.PointOfSale)] [DomainMappingConstraint(AppType.PointOfSale)]
[RateLimitsFilter(ZoneLimits.PublicInvoices, Scope = RateLimitsScope.RemoteAddress)] [RateLimitsFilter(ZoneLimits.PublicInvoices, Scope = RateLimitsScope.RemoteAddress)]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> ViewPointOfSale(string appId, public async Task<IActionResult> ViewPointOfSale(string appId,
PosViewType? viewType = null, PosViewType? viewType = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? amount = null, [ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? amount = null,
@@ -329,6 +330,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
} }
[HttpPost("/apps/{appId}/pos/form/{viewType?}")] [HttpPost("/apps/{appId}/pos/form/{viewType?}")]
[IgnoreAntiforgeryToken]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> POSForm(string appId, PosViewType? viewType = null) public async Task<IActionResult> POSForm(string appId, PosViewType? viewType = null)
{ {
var app = await _appService.GetApp(appId, AppType.PointOfSale); var app = await _appService.GetApp(appId, AppType.PointOfSale);
@@ -373,6 +376,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
} }
[HttpPost("/apps/{appId}/pos/form/submit/{viewType?}")] [HttpPost("/apps/{appId}/pos/form/submit/{viewType?}")]
[IgnoreAntiforgeryToken]
[XFrameOptions(XFrameOptionsAttribute.XFrameOptions.Unset)]
public async Task<IActionResult> POSFormSubmit(string appId, FormViewModel viewModel, PosViewType? viewType = null) public async Task<IActionResult> POSFormSubmit(string appId, FormViewModel viewModel, PosViewType? viewType = null)
{ {
var app = await _appService.GetApp(appId, AppType.PointOfSale); var app = await _appService.GetApp(appId, AppType.PointOfSale);