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
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 25 additions and 27 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -117,7 +117,7 @@ namespace BTCPayServer.Hosting
services.AddSingleton<LightningAddressService>();
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 XXSSProtectionAttribute());
o.Filters.Add(new ReferrerPolicyAttribute("same-origin"));

View file

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

View file

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