Duplicate X-Content-Type-Options headers both with the value nosniff

Created on 22 February 2017, almost 8 years ago
Updated 27 January 2023, almost 2 years ago

Problem/Motivation

In #462950: Mitigate the security risks that come from IE, Chrome and other browsers trying to sniff the mime type β†’ we added

  # Disable content sniffing, since it's an attack vector.
  Header always set X-Content-Type-Options nosniff

To the .htaccess file. We also have

    // Prevent browsers from sniffing a response and picking a MIME type
    // different from the declared content-type, since that can lead to
    // XSS and other vulnerabilities.
    // https://www.owasp.org/index.php/List_of_useful_HTTP_headers
    $response->headers->set('X-Content-Type-Options', 'nosniff', FALSE);

in \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond().

It needs to be in both places because we want the nosniff header on files not served by Drupal's index.php, for example, images.

However, if I get the home page of my local dev build I see the following headers:

Cache-Control:must-revalidate, no-cache, private
Connection:Keep-Alive
Content-Encoding:gzip
Content-language:en
Content-Length:1619
Content-Type:text/html; charset=UTF-8
Date:Wed, 22 Feb 2017 09:16:54 GMT
Expires:Sun, 19 Nov 1978 05:00:00 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.23 (Unix) PHP/7.1.0 LibreSSL/2.2.7
Vary:Accept-Encoding
X-Content-Type-Options:nosniff
X-Content-Type-Options:nosniff
X-Drupal-Cache:MISS
X-Drupal-Cache-Contexts:languages:language_interface route theme url.path url.query_args user.permissions user.roles:authenticated
X-Drupal-Cache-Tags:block_view config:block.block.stark_admin config:block.block.stark_branding config:block.block.stark_local_actions config:block.block.stark_local_tasks config:block.block.stark_login config:block.block.stark_messages config:block.block.stark_page_title config:block.block.stark_tools config:block_list config:system.menu.admin config:system.menu.tools config:system.site config:user.role.anonymous config:user.settings http_response rendered
X-Drupal-Dynamic-Cache:HIT
X-Frame-Options:SAMEORIGIN
X-Generator:Drupal 8 (https://www.drupal.org)
X-Powered-By:PHP/7.1.0
X-UA-Compatible:IE=edge

As you can see the X-Content-Type-Options header is duplicated.

This problem also causes \Drupal\system\Tests\Routing\RouterTest to fail for me locally with:

Fail      Other      RouterTest.php      40 Drupal\system\Tests\Routing\RouterT
    Value 'nosniff,nosniff' is equal to value 'nosniff'.

Which is how I found this problem.

Proposed resolution

I think the we need to fix the .htaccess rule so this does not occur. Because the line in \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond() makes this work for other webservers for every delivered via index.php.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

The root .htaccess file now unsets the X-Content-Type-Options header before setting it again β†’ , to prevent duplicate headers in some configurations of Apache. Site owners should update their .htaccess files with this change to avoid duplicated headers.

πŸ› Bug report
Status

Fixed

Version

10.1 ✨

Component
BaseΒ  β†’

Last updated 1 day ago

Created by

πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

Live updates comments and jobs are added and updated live.
  • Security Advisory follow-up

    This tag is to be applied to issues where an official security release has been made, but the fix needs to be ported to the development version of the code.

  • Security improvements

    It makes Drupal less vulnerable to abuse or misuse. Note, this is the preferred tag, though the Security tag has a large body of issues tagged to it. Do NOT publicly disclose security vulnerabilities; contact the security team instead. Anyone (whether security team or not) can apply this tag to security improvements that do not directly present a vulnerability e.g. hardening an API to add filtering to reduce a common mistake in contributed modules.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Status changed to Needs review almost 2 years ago
  • First commit to issue fork.
  • Status changed to RTBC almost 2 years ago
  • πŸ‡³πŸ‡±Netherlands idebr

    #85 Change record and Release note is available, setting back to RTBC

  • πŸ‡ΊπŸ‡ΈUnited States xjm

    Asking from complete ignorance: Is there any web.config equivalent we should consider here for parity?

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    @xjm Great question. https://serverfault.com/a/904278 suggests it is both possible to do and to prevent duplicate headers, as in the .htaccess changes in this issue. However I think it would be necessary for someone running IIS to test this before we commit such a change.

  • Status changed to Needs work almost 2 years ago
  • πŸ‡ΊπŸ‡ΈUnited States xjm

    Great, let's do that then. Thanks!

  • Status changed to RTBC almost 2 years ago
  • πŸ‡¨πŸ‡¦Canada Liam Morland Ontario, CA πŸ‡¨πŸ‡¦

    The web.config file is completely different. This should be done in a follow-up ticket.

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    Also web.config does not currently do anything with X-Content-Type-Options so it can't be causing the same bug. This fact might be a bug on it's own but it shouldn't be solved here as this issue is about Apache having duplicate headers.

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    Also a decent number of IIS articles recommend setting this on the site level in the server (i.e. not using web.config - see https://dotnetcoretutorials.com/2017/01/20/set-x-content-type-options-as... for an example).

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    Opened πŸ“Œ Set X-Content-Type-Options header in IIS web.config Active to discuss #99 through #104.

  • πŸ‡ΊπŸ‡ΈUnited States xjm

    If IIS doesn't have it set at all yet, then @catch, @longwave, and I agreed with a followup.

    However, please make note that in general, any issues for .htaccess should consider web.config in the same issue scope. In this case, probably the previous issue should have. We've had frequent issues over the years (both public hardenings and private security issues) where the web.config has not been well-maintained and has not gotten the same fixes, so we always need to evaluate it @Liam Morland. It doesn't get excluded just because it's in a different file, and how issues are scoped is a release management decision.

    • xjm β†’ committed e7b87b5c on 10.1.x
      Issue #2854817 by Liam Morland, longwave, alexpott, JoshaHubbers,...
  • Status changed to Fixed almost 2 years ago
  • πŸ‡ΊπŸ‡ΈUnited States xjm
      # https://httpd.apache.org/docs/current/mod/mod_headers.html.
      Header onsuccess unset X-Content-Type-Options
      Header always set X-Content-Type-Options nosniff
    

    Since we're unsetting all values for the header but only resetting nosniff, I checked to verify that this was the only possible value for it. Per https://fetch.spec.whatwg.org/#x-content-type-options-header:

    1. Let values be the result of getting, decoding, and splitting `X-Content-Type-Options` from list.
    2. If values is null, then return false.
    3. If values[0] is an ASCII case-insensitive match for "nosniff", then return true.
    4. Return false.

    So at least in the present spec, this solution is OK.

    Adding credit for @alexpott for code review and the initial issue report, @Liam Morland, @alex-b, and @Mile23 for work on the patch, @longwave for review and work on the CR and release note, @JoshaHubbers for work on the CR and release note, @effulgentsia for review and work on the patch, @Wim Leers for review and issue triage, and @mr.baileys for review and manual testing. I did not credit @idebr for merging HEAD with no other changes.

    I was wondering what happened to the earlier attempts at test coverage, but it seems #3226187: Enable mod_headers on Apache β†’ needs to be addressed for that.

    Release notes should always tell the user:

    1. What it was before
    2. What changed
    3. Who might be affected
    4. What they should do as a result

    The release note was missing the second two, so I added a sentence for that. I similarly expanded the content of the CR with background information on why this header is used in the first place, and put in a code snippet to show exactly what site owners should update. Finally, I linked the CR from the release note.

    Committed and pushed to 10.1.x. Thanks!

  • πŸ‡ΊπŸ‡ΈUnited States xjm

    Added the release note to the draft release notes doc.

  • πŸ‡ΊπŸ‡ΈUnited States greggles Denver, Colorado, USA

    I appreciate all the work on this issue. Thanks to everyone involved.

    However, please make note that in general, any issues for .htaccess should consider web.config in the same issue scope. In this case, probably the previous issue should have. We've had frequent issues over the years (both public hardenings and private security issues) where the web.config has not been well-maintained and has not gotten the same fixes, so we always need to evaluate it @Liam Morland. It doesn't get excluded just because it's in a different file, and how issues are scoped is a release management decision.

    From the security team perspective, I support this paragraph from comment #106. We regularly will get reports "htaccess provides X security benefit that is missing in web.config" and then are in the awkward situation of deciding whether to do a security advisory and release for a fix that affects relatively few people.

    I think we should consider it a bug if web.config and htaccess' behavior is different.

  • πŸ‡ΊπŸ‡ΈUnited States xjm

    Published the CR.

  • πŸ‡³πŸ‡±Netherlands idebr

    Is this commit eligible for backporting as it is a bugfix?

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    Changes to .htaccess are usually only made in minor releases unless they are critical. This is not a critical bug - the duplicate header might cause warnings, but it has no actual impact on anything - so to me this is not eligible for backport.

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024