Open Bug 1600556 Opened 5 years ago Updated 3 years ago

webRequest.onHeadersReceived sometimes receives one merged header instead of separate header lines

Categories

(WebExtensions :: Request Handling, task, P3)

Desktop
Windows
task

Tracking

(firefox-esr68 affected, firefox71 affected, firefox72 affected, firefox73 affected)

Tracking Status
firefox-esr68 --- affected
firefox71 --- affected
firefox72 --- affected
firefox73 --- affected

People

(Reporter: chu-jun.dong, Unassigned, NeedInfo)

Details

Attachments

(1 file)

505.07 KB, application/octet-stream
Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36

Steps to reproduce:

require permission to inject my script by hacking the content security policy to append 'nonce' attribute with a specific value, so the <script> node (we injected to page) with the same nonce attribute are allowed to execute.

Actual results:

the Gmail page hangs

Expected results:

Enter the Gmail page

I am attempting to confirm this issue, but the bug is lacking some detailed steps that I could use to reproduce it. Can you come up with a list of actions that I would be required to take in order to get the unexpected hang of the Gmail webpage?

Thank you for your contribution!

Flags: needinfo?(chu-jun.dong)

Bodea
Sorry for not detailed enough description
if you want to reproduce the issue, here is the steps:
1. revise the http head during the event webRequest.onHeadersReceived.
Our code is
chrome.webRequest.onHeadersReceived.addListener(this._onHeadersReceived.bind(this),
{ urls: ["http:///", "https:///"] },
["blocking", "responseHeaders"]);
2. in the request's onHeadersReceived listener, hack the content security policy to append 'nonce' attribute
our code is
responseHeaders.forEach(function (head) {
if (isCspHeader(head.name.toUpperCase())) {
var csp = head.value;
// append "nonce-UftNonceMagicAllowInlineScript" to whitelist our injected script later, if there is no 'unsafe-inline'
// or there is any existing nonce.
// 'nonce' will make 'unsafe-inline' being ignored, and with 'unsafe-inline' soley our inline script is good to run.
if (csp.indexOf("unsafe-inline") < 0 || csp.indexOf('nonce-') >= 0
|| csp.indexOf("chrome-extension: 'unsafe-inline'") >= 0) {
this._logger.trace("original header value:" + csp);
csp = csp.replace('script-src', "script-src 'nonce-xxxx'"); // if you remove the ' around nonce-xxxx the isue would disapear.
this._logger.trace("replaced header value:" + csp);
replaced = true;
}
head.value = csp;
}
}.bind(this));

Flags: needinfo?(chu-jun.dong)

I still cannot confirm it with the provided information due to the lack of technical skills on how to actually make those steps reality. I will set this bug's component as (Firefox) Security. Please give it a more appropriate one if incorrect and NI me if further testing is needed.
Reporter, than you for your contribution!

Component: Untriaged → Security
Component: Security → Untriaged
Product: Firefox → WebExtensions

Forgive me, if it is the case please download our newest trail version UFT one(https://www.microfocus.com/en-us/products/uft-one/overview).
Then open then the firefox ensuring the extension is enabled, open Gmail. You can see the page hanging.
You could resolve the issue by changing the code
at line 479 csp = csp.replace('script-src', "script-src 'nonce-UftNonceMagicAllowInlineScript'");
When you remove the ' around nonce-UftNonceMagicAllowInlineScript, at which the code should looks like
csp = csp.replace('script-src', "script-src nonce-UftNonceMagicAllowInlineScript");

The issue just happens in recent versions of Firefox, and all the other Browser works fines. So probably it is caused by some change in your side. Since it is the standard to add ' around the customized specifier. So I believe there is some need for you to have an investigation.

If you have trouble, please feel free to reach me and I' glad to help to improve your products.

I can now confirm the issue since I reproduced it an all the main versions of Firefox. made a trial account on https://home.software.microfocus.com/, downloaded and installed the app while having the Firefox set as default browser and installed the recommended addon. When attempting to open Gmail, the website got stuck during loading after login.

I also attempted reproduction on Mac OS but could not find an installer, so I will assume this is a Windows-only issue.

Status: UNCONFIRMED → NEW
Ever confirmed: true
OS: Unspecified → Windows
Hardware: Unspecified → Desktop

Based on comment 2, I tried to create a minimal reproduction, as follows, and visited Gmail without seeing the reported issue:

chrome.webRequest.onHeadersReceived.addListener(({responseHeaders}) => {
  let replaced = false;
  responseHeaders.forEach(head => {
    if (head.name.toUpperCase() === 'CONTENT-SECURITY-POLICY' && (!head.value.includes('unsafe-inline') || head.value.includes('nonce-'))) {
      head.value = head.value.replace('script-src', "script-src 'nonce-xxxx'");
      console.log(`Replaced CSP with: ${head.value}`);
      replaced = true;
    }
  });
  if (replaced) return {responseHeaders};
}, {urls: ['*://*/*']}, ['blocking', 'responseHeaders']);

I tried to sign up, but did not get an e-mail. Could you share the add-on package (i.e. the xpi file) that causes the issue?

And when the bug occurs, are any errors showing up in the browser console? What are the final response headers of Gmail? With the description here, I would not be surprised if "Gmail hangs" means "Gmail fails to load when I add a CSP that blocks Gmail's required resources". That would not be a bug in Firefox, but in your extension.

Flags: needinfo?(chu-jun.dong)
Attached file WebExtension.xpi

this is our extension

Flags: needinfo?(chu-jun.dong)

The request is always 200 OK and the console log has the very same error message "Content Security Policy: The page's settings blocked the loading of a resource at inline ("script-src")." No matter the Gmail could load or not.
And on our side, with version 60 the with the same code, the Gmail could load.
I've attached the extension.xpi in the attachment.

Reproduced, even without your extension, but with my example from comment 6.

Gmail replies with two CSP headers, the second one being stricter than the first one:

content-security-policy: script-src ... 'unsafe-inline' ...
content-security-policy: script-src 'nonce-aOhqtAOxdAyI0PsFEYLklg' ... 'unsafe-inline' ...

When the "hang" issue occurs, the scripts from Gmail are blocked by the CSP.
When that happens, the extension logs the following (note that the two CSP headers are joined by a comma).

script-src 'nonce-UftNonceMagicAllowInlineScript' ... 'unsafe-inline' ... , script-src 'nonce-aOhqtAOxdAyI0PsFEYLklg' ... 'unsafe-inline' ...

There are two bugs here:

  1. We should probably not merge the headers, but we still do somehow - we need to investigate this.
  2. Your extension rewrites one CSP directive based on a condition on the whole header. This is flawed, as a CSP string can perfectly contain more than one directive, either by the server, or as a result of the bug from the previous line. (and you should not use a hard-coded nonce, because anyone else can use that, which weakens the security of Gmail.)

Although you can try to work around this bug by improving your CSP parser, the more reliable and secure solution would be to insert the extension script in the page instead of using inline scripts with a nonce. moz-extension: (and chrome-extension:)-URLs are allowed to bypass the CSP. Here is an example: https://github.com/Rob--W/dont-slack-redir/blob/e5646287671cb202193d51c03b770c3b40eb3bd2/contentscript.js#L13-L28

We didn't only inject script by files but by script string most of the time. The modification would be a huge risk for our products. Besides, multiple nonces could work on firefox before, would you fix the merging issue later?

I am setting the component as Compatibility so it would not remain as Untriaged. Please give it a better component if incorrect. Thanks.

Component: Untriaged → Compatibility

I'll investigate why we are merging the headers.

Component: Compatibility → Request Handling
Flags: needinfo?(rob)
Priority: -- → P2
Summary: Gmail hang when appending new key wtih "'" the script-src during onHeadersReceived event → webRequest.onHeadersReceived sometimes receives one merged header instead of separate header lines
Severity: normal → N/A
Type: defect → task
Priority: P2 → P3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: