laravel-debugbar icon indicating copy to clipboard operation
laravel-debugbar copied to clipboard

Debugbar Not Showing Due To CSP

Open sys-auditing opened this issue 3 years ago • 9 comments
trafficstars

Hi,

i'm using the laravel-debugbar and works like a charm, but when adding CSP the debugbar stop showing.

Laravel : "laravel/framework": "^8.0" "spatie/laravel-csp": "2.6.4",

Debugbar : "barryvdh/laravel-debugbar": "^3.5"

Thank's for the help

sys-auditing avatar Jun 03 '22 15:06 sys-auditing

This is probably a problem with a missing nounce @barryvdh did you ever find a solution for this (except for enabling unsafe-inline in debug state) ?

robov avatar Jul 04 '22 17:07 robov

The bot marked the old ticket as stale: #1016

luckydonald avatar Jul 27 '22 12:07 luckydonald

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this issue is still present on the latest version of this library on supported Laravel versions, please let us know by replying to this issue so we can investigate further. Thank you for your contribution! Apologies for any delayed response on our side.

stale[bot] avatar Nov 02 '22 03:11 stale[bot]

.

luckydonald avatar Nov 04 '22 03:11 luckydonald

I mean I could just use hashes to allow just the stuff it writes.

The problem is phpdebugbar.addDataSet({…}, "…") in the last added script tag.

Which I could work around by adding this in a middleware:

            $content = $response->content();
            $debugBarVar = 'phpdebugbar';  // this was coming from some config, but I forgot from where.
            preg_match('/(?P<openScriptTagStart><script )(?P<openScriptTagEnd>.*?>)(?P<scriptContentBefore>\n.*?)\n'.$debugBarVar.'\.addDataSet\((?P<data>.+), "(?P<param>\w+)"\);(?P<scriptContentAfter>\n.*?)(?P<closeScriptTag><\/script>)/s', $response->content(), $matches);
            $openScriptTagStart = $matches['openScriptTagStart'];
            $data = $matches['data'];
            $param = $matches['param'];
            $openScriptTagEnd = $matches['openScriptTagEnd'];
            $scriptContentBefore = $matches['scriptContentBefore'];
            $scriptContentAfter = $matches['scriptContentAfter'];
            $closeScriptTag = $matches['closeScriptTag'];
            $dataEncoded = htmlspecialchars($data);
            $paramEncoded = htmlspecialchars($param);
            $old = $matches[0];
            $new = "$openScriptTagStart data-$debugBarVar-data=\"$dataEncoded\" data-$debugBarVar-param=\"$paramEncoded\" $openScriptTagEnd{$scriptContentBefore}\n";
            $new .= "var {$debugBarVar}Data = document.querySelector('script[data-$debugBarVar-data][data-$debugBarVar-param]').attributes;\n";
            $new .= "$debugBarVar.addDataSet(JSON.parse({$debugBarVar}Data['data-$debugBarVar-data'].value), {$debugBarVar}Data['data-$debugBarVar-param'].value);\n";
            $new .= "{$scriptContentAfter}$closeScriptTag";
            $content = $content->replace($old, $new)->value();
            $original = null;
            if ($response instanceof \Illuminate\Http\Response && $response->getOriginalContent()) {
                $original = $response->getOriginalContent();
            }

            // Update the new content and reset the content length
            $response->setContent($content);
            $response->headers->remove('Content-Length');

            // Restore original response (eg. the View or Ajax data)
            if ($original) {
                $response->original = $original;
            }

What it does is using a regex (uh oh) to grab the values of that. Then those get applied as two attributes to the script tag instead: data-phpdebugbar-data="{…}" and data-phpdebugbar-param="…".

It can easily be loaded with

JSON.parse(document.querySelector('script[data-phpdebugbar-data]').attributes['data-$debugBarVar-data'].value))

Now the content of the <script> does no longer change, and a hash can be used to whitelist the occurrence in the CSP; In my case '\'sha256-Q59u6hqnWqFUgu6e2Pg5p1xxto/mrNsJbgpsZsCVVY4=\''.


The only problem remaining now, is to get the middleware in the correct order so $response->content() actually is with the debug bar already injected.

luckydonald avatar Jan 05 '23 00:01 luckydonald

I am running into this too. I could really use a clean solution to setting a nonce for any styles/scripts that debugbar injects inline. This seems to be a recurring theme

dasch88 avatar Jan 18 '23 15:01 dasch88

Only semi workaround for this (when using spatie/laravel-csp) is to either:

  • disable it locally via setting CSP_ENABLED to false
  • report only locally i.e. call $this->reportOnly() within your policy definition class

Both options will allow debug bar to display.

ultrono avatar Feb 05 '23 20:02 ultrono

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this issue is still present on the latest version of this library on supported Laravel versions, please let us know by replying to this issue so we can investigate further. Thank you for your contribution! Apologies for any delayed response on our side.

stale[bot] avatar Jun 18 '23 15:06 stale[bot]

What about https://github.com/barryvdh/laravel-debugbar/pull/1464?

parallels999 avatar Sep 18 '23 21:09 parallels999