Closed joadan closed 6 months ago
As I have written, for now the only way we manage to run the chart with tooltips on data points is to have unsafe eval
in CSP enabled. But there is no way that I now to check if actually the hash we generate from the tooltip formatter written in source is the same as the JS code that ends up in the running application. The formatter also gets only the code part, without <script>
tags, so I don't see a way to use nonce
in CSP. I think that keeping the unsafe eval
for the whole Blazor application just because of only these formatters is not very safe idea...
In blazor server we cannot run the .net formatters because the format function in apexchart.js is synchronously, while we need async in order to call blazor server. In order to set a javascript formatter we need to run javascript eval function to create the formatter function on the javascript side.
Currently we don't have any other solution to this problem.
I'm not familiar with CSP hash, could you explain how that could help.
Using CSP with hash means that the only JS code that can be evaluated at runtime is the code which hash matches the hash specified in the CSP. That way if we hash this code:
function(value, opts) { if (value === undefined) {return '0';} return value.toFixed(3)}
then only this piece of JS code can be run in the app. But it needs to be exactly the same when generating a hash and then in the deployed code - same whitespace, same capitalization, same everything for it to work. It protects from any kind of possible XSS attacks in the application.
Looking at the code and I believe we should be able to support custom tooltips with out any eval of javascript. Would that help?
Using CSP with hash means that the only JS code that can be evaluated at runtime is the code which hash matches the hash specified in the CSP. That way if we hash this code:
function(value, opts) { if (value === undefined) {return '0';} return value.toFixed(3)}
then only this piece of JS code can be run in the app. But it needs to be exactly the same when generating a hash and then in the deployed code - same whitespace, same capitalization, same everything for it to work. It protects from any kind of possible XSS attacks in the application.
I get that part, question is how would it work in the component?
We have upgraded the Blazor-ApexCharts nuget to 2.3.2 and currently we have this CSP:
add_header Content-Security-Policy "default-src 'self' http: https: data: blog: 'unsafe-inline'; script-src 'self'; always;";
And this is our custom formatter:
Tooltip = new Tooltip
{
Y = new TooltipY
{
Formatter = @"function(value, opts) { if (value === undefined) {return '0';} return value.toFixed(3)}"
},
HideEmptySeries = false,
},
And still when the chart loads it producess this error:
EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
at eval (<anonymous>)
at Object.<anonymous> (https://example.com/_content/Blazor-ApexCharts/js/blazor-apexcharts.js:413:34)
at JSON.parse (<anonymous>)
at Object.parseOptions (https://example.com/_content/Blazor-ApexCharts/js/blazor-apexcharts.js:408:21)
at Object.renderChart (https://example.com/_content/Blazor-ApexCharts/js/blazor-apexcharts.js:202:28)
at https://example.com/_framework/blazor.server.js:1:3244
at new Promise (<anonymous>)
at y.beginInvokeJSFromDotNet (https://example.com/_framework/blazor.server.js:1:3201)
at Yt._invokeClientMethod (https://example.com/_framework/blazor.server.js:1:61041)
at Yt._processIncomingData (https://example.com/_framework/blazor.server.js:1:58516)
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
at Microsoft.JSInterop.JSObjectReferenceExtensions.InvokeVoidAsync(IJSObjectReference jsObjectReference, String identifier, Object[] args)
at ApexCharts.ApexChart`1.InvokeVoidJsAsync(String identifier, Object[] args)
at ApexCharts.ApexChart`1.RenderChartAsync()
at ApexCharts.ApexChart`1.OnAfterRenderAsync(Boolean firstRender)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
Is there anything we are doing wrong right now?
Hi,
Sorry for the confusion.
Yes the formatters will require javascript eval.
However you have one option to use the Custom Tooltip function. This will enable you to specify a render fragment for the tooltip in blazor, this will not require a javascript eval. https://apexcharts.github.io/Blazor-ApexCharts/features/tooltip
Ok, thanks! That worked. We have added <ApexPointTooltip>
inside <ApexChart>
and that allowed us to create the custom tooltip that we need.
So to summarize, if someone stumbles upon this issue: There is no need to define Tooltip in ApexChartsOptions with a JS formatter. Keeping the CSP mentioned above works when just defining a custom tooltip with the ApexPointTooltip component.
P.S. the tooltip seems to be cached in Firefox, so we needed to clear all data to actually see the new one working.
Thanks
Right now in Blazor SS with Blazor-ApexCharts, we need to enable
unsafe eval
in NGINX otherwise the pages with charts crash. Is it planned to also allow .NET Formatters for SS? Or is it possible to use CSP hash for the formatter?We tried with a hash, but we are getting this error when opening a page with a chart:
Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'sha256-[HASH]'".
Is it because in the published app the formatter script is saved differently from the source code and the hashes don't actually match?Originally posted by @twojnarowski in https://github.com/apexcharts/Blazor-ApexCharts/issues/37#issuecomment-1932264816