daattali / shinyjs

💡 Easily improve the user experience of your Shiny apps in seconds
https://deanattali.com/shinyjs
Other
737 stars 118 forks source link

Possible to move inline scripts to a .js file for easier CSP implementations? #274

Open LDSamson opened 1 month ago

LDSamson commented 1 month ago

Not sure if this is even possible, but I thought it is worth to ask.

When calling shinyjs::useShinyjs, many functions are injected inline in the UI. This is a problem when implementing a strict CSP for a Shiny web application, since inline scripts are blocked by default. Would it be possible that these functions are loaded by calling a script file in the package inst folder instead of injecting them inline? Maybe using a variant of the inject.js script that was previously present in the package, to create the needed calls dynamically?

May be related to #101

On a sidenote: I suspect that the documentation on how to include shinyjs using a HTML template is outdated, since the function inject.js is not included in the package anymore: https://github.com/daattali/shinyjs/blob/0648faa0dc985a5be55bbc745fe042056a0ecfc3/vignettes/shinyjs-usage.Rmd#L167

daattali commented 1 month ago

Thanks for the sidenote, I'll look into that.

Regarding the CSP issue: I have not run into this problem before, but you're right it should be addressed. Loading the code via a script is definitely an option. I based on 1 mint of research it seems that perhaps it's possible to include a nonce in the script tag to allow it. Are you familiar with that? Passing a nonce parameter to useShinyjs could be another possible solution, what do you think?

LDSamson commented 1 month ago

Thanks for the quick response and taking the request into consideration.

Setting an nonce is also possible but, as far as my knowledge goes, setting it securely is not trivial. It needs to be set both within the Content-Security-Policy http header in the running web server and in every (inline) script. It needs to be a random string, that refreshes each time the web page refreshes, otherwise an attacker can just add the same nonce to an injected script and it will run without problems.

I think by far the best solution (and easiest at least for Shiny app developers and IT security departments) would be to place the scripts in an external file. Then no nonce or hash is needed. If this is not possible, it would indeed still be nice if we can set an nonce in every script tag.

The third option is to create a hash of the exact inline script, which can be added to the CSP. Downside is that this is a lot of manual work for the developer, and hard to maintain.