craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.28k stars 635 forks source link

Duplicate dashboard HTTP headers #3159

Closed XhmikosR closed 6 years ago

XhmikosR commented 6 years ago

Description

I'm already setting my security headers via the web/.htaccess. There I set X-Frame-Options and X-Content-Type-Options along with other headers. Every dashboard page includes duplicate headers because it seems you are adding the headers too.

Steps to reproduce

  1. Set X-Frame-Options: DENY and X-Content-Type-Options: nosniff in web/.htaccess
  2. Visit the dashboard and check for the HTTP headers
  3. You will see duplicate X-Frame-Options and X-Content-Type-Options headers

Additional info

Wouldn't it be better if you checked for the presence of these headers before adding them?

brandonkelly commented 6 years ago

Can you do a test for me? Create a test.php file in your web root with this:

<?php

print_r(headers_list());

Then access it in your browser. Does the output include your X-Frame-Options header?

XhmikosR commented 6 years ago

@brandonkelly: you mean in web folder, right?

brandonkelly commented 6 years ago

Sure, wherever your server’s web root is. Probably web/ if you didn’t change that.

XhmikosR commented 6 years ago
Array ( [0] => X-Powered-By: PHP/7.2.4 ) 

The frontend doesn't have this issue, I only noticed the issue with the control panel pages.

brandonkelly commented 6 years ago

Yeah that’s what I figured but just wanted to be sure.

So the answer unfortunately is that we can’t fix this from PHP as PHP isn’t aware of your X-Frame-Options and X-Content-Type-Options headers in the first place. So you will need to update your server configuration so that those headers don’t get sent for Control Panel requests.

XhmikosR commented 6 years ago

I see, thanks for the reply.

Unfortunately, working with .htaccess can become quite messy and there doesn't seem to be another place one could use a separate .htaccess for the control panel requests.

brandonkelly commented 6 years ago

Looks like the SetEnvIf directive could work for you, per https://serverfault.com/a/108519

XhmikosR commented 6 years ago

Yeah, I'll figure something out, but my problem is still valid. It's hard to keep 2 sets of files in one file.

BTW, XFO is ignored if CSP is sent.

I know this is a long shot, but I wish I could use an .htaccess for the backend separately.

brandonkelly commented 6 years ago

Technically you can. Create a new web-cp/ directory alongside your web/ directory and copy your web/index.php file into it:

my-craft-project.dev/
├── web/
│   ├── index.php
│   └── ...
└── web-cp/
    └── index.php

Then create a new web server / virtual host, such as cp.mysite.com, pointed at your new web-cp/ direcotry.

Then set the baseCpUrl config setting in config/general.php:

'baseCpUrl' => 'https://cp.mysite.com/',

Then your CP requests can go through cp.mysite.com, and you can give them separate .htaccess rules than your main site.

(Note that even if you set the baseCpUrl setting, your CP requests will still need to include the cpTrigger – e.g. https://cp.mysite.com/admin/....)

XhmikosR commented 6 years ago

Thanks for the replies, I really appreciate it. :)

Still, I don't think it's a good solution if you pay per the number of apps. So, if I have 3 apps (testing, staging, production) I'd need 2x the apps for this.

XhmikosR commented 6 years ago

@brandonkelly: I played a bit with this and it seems I can't match REQUEST_URI because that is always index.php?p=.

So this doesn't work:

<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff" "expr=%{REQUEST_URI} !~ m#^/admin/?#"
</IfModule>

Any suggestions or the pattern that this follows would help.

Thanks!

XhmikosR commented 6 years ago

Nvm, I just figured it out. This seems to do the job:

"expr=%{QUERY_STRING} !~ m#^p=admin#"
XhmikosR commented 6 years ago

I'm not sure if this is perfect though.

Also, I wonder, should https://foo.bar/index.php?p=page work at all?