SOLVED htaccess Header Set doesn't set

Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
I've tried setting a few basic security headers from an htaccess file. For PHP and HTM (no L) files with rewrites I don't see the headers being set in Chrome. HTML files, JPG images, etc seem to receive the set headers as expected. So php and rewriting seems to be the issue at the moment. Here are the headers I'm trying to set along with a basic forced https on rule:

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Header set Strict-Transport-Security "max-age=300; includeSubDomains" env=HTTPS
Header set Content-Security-Policy "upgrade-insecure-requests" env=HTTPS
Header set X-Content-Type-Options "nosniff"
Header unset "X-Powered-By"
<FilesMatch "\.(htm|html|php)$">
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
</FilesMatch>

Max age 300 is just for testing so please ignore the specific values unless the syntax is wrong. I can't force strict transport security on all domain names on the server for example. This particular domain has a purchased SSL. Server is GoDaddy dedicated. Possible WHM setting conflicts could be "Symlink Protection = On" and "Use a Global DCV Passthrough instead of .htaccess modification = On".

How do I get PHP and sym HTM links to show these headers?

Thanks.
 
Last edited:
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
I was able to set these using php as a fallback. If the headers are not set then set them just prior to printing the page. If there's a better way please share. Thanks.

PHP:
if (!headers_sent()) {
    $headers_list = headers_list();
    if (!in_array("X-XSS-Protection", $headers_list)) {header("X-XSS-Protection: 1; mode=block"); }
    if (!in_array("X-Content-Type-Options", $headers_list)) {header("X-Content-Type-Options: nosniff"); }
    if (!in_array("X-Frame-Options", $headers_list)) {header("X-Frame-Options: SAMEORIGIN"); }
    if (!in_array("Strict-Transport-Security", $headers_list)) {header("Strict-Transport-Security: max-age=2592000; includeSubDomains"); }
    if (!in_array("Content-Security-Policy", $headers_list)) {header("Content-Security-Policy: upgrade-insecure-requests"); }
    if (!in_array("Referrer-Policy", $headers_list)) {header("Referrer-Policy: strict-origin-when-cross-origin"); }
}
 
Last edited:

fuzzylogic

Well-Known Member
Nov 8, 2014
154
95
78
cPanel Access Level
Root Administrator
And once you get mod_headers working in your htaccess files...
Your
Code:
<FilesMatch "\.(htm|html|php)$">
    Header set Pragma "no-cache"
</FilesMatch>
syntax is valid.
 

cPWilliamL

cP Technical Analyst II
Staff member
May 15, 2017
258
30
103
America
cPanel Access Level
Root Administrator
As fuzzylogic pointed out, you'll need to ensure mod_headers is installed. On EA4 systems, you'll need to install `ea-apache24-mod_headers'. This could also be due to your PHP handler. Would you happen to be using CGI? If so, please see the Apache doc below:
Apache Tutorial: Dynamic Content with CGI - Apache HTTP Server Version 2.4
Missing environment variables
If your CGI program depends on non-standard environment variables, you will need to assure that those variables are passed by Apache.

When you miss HTTP headers from the environment, make sure they are formatted according to RFC 2616, section 4.2: Header names must start with a letter, followed only by letters, numbers or hyphen. Any header violating this rule will be dropped silently.
If using CGI, it's likely your variables are being stripped as a security measure. They'll need to be defined directly in an Apache configuration, such as userdata includes, or you'll need to use another handler:
Modify Apache Virtual Hosts with Include Files - EasyApache 4 - cPanel Documentation
 
  • Like
Reactions: John Napoletano
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
Do you have mod_headers installed in easyapache4?
htaccess "Header set" won't work without it.
WHM Home > Software > EasyApache4 > View all packages (currently installed)

Apache 2.4

mod_bwlimited
mod_cgi
mod_deflate
mod_expires
mod_headers
mod_mpm_prefork
mod_ruid2
mod_security2
mod_ssl
mod_unique_id


I didn't want to paste the PHP and Others packages installed, not sure if I should post them here in a public forum. This is a "custom" profile but can be altered if needed. I noticed that the recommended profiles in WHM are a bit different. Security is always of concern to me for Ecommerce and Wordpress website builds, MariaDB use etc.

I read the comments about CGI as a possible issue. Is that all saying that adding the keyword "always" should fix the problem given the packages listed, package changes recommended instead?
 
Last edited by a moderator:
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
I didn't see anything in the Apache CGI documentation about "always". Did it correct your issue? Did temporarily changing the PHP handler correct the issue?
The "always" condition is mentioned in the mod_headers doc. I have not tried it yet as others have pointed to CGI as the issue. The PHP header method is working. I'll have to move onto HTTP2 and review package requirements before revisiting this issue.

Thanks for your input!
 
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
@cPWilliamL
@fuzzylogic

OK I believe I found the solution and it passes the necessary Google HSTS test up to the "preload" status (I don't want to preload). The issue seems to be with htaccess redirecting and not specific to CGI or my Apache settings. Notice the "E=HTTPS" flag on the www redirect. Here is the htaccess HSTS part to simplify.

Code:
# Redirect to https
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect to www
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteRule (.*) https://www.yourdomain.com/$1 [E=HTTPS,R=301,L]

# Security header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
Google's tool tipped me off that they want to see two redirects not one. The env=HTTPS environment variable wasn't working as expected. So I used the E=HTTPS flag on the www redirect to set the env=HTTPS environment variable on the next request.

Apache 2.4 Env Docs
Environment Variables in Apache - Apache HTTP Server Version 2.4

Test with these two:
HSTS Preload List Submission (Google)
Analyse your HTTP response headers

If anyone wants to add to this or confirm the fix feel free. I doubt I'm the only one having trouble with this.
 
Last edited:

Nirjonadda

Well-Known Member
May 8, 2013
762
28
78
cPanel Access Level
Root Administrator
@cPWilliamL
@fuzzylogic

OK I believe I found the solution and it passes the necessary Google HSTS test up to the "preload" status (I don't want to preload). The issue seems to be with htaccess redirecting and not specific to CGI or my Apache settings. Notice the "E=HTTPS" flag on the www redirect. Here is the htaccess HSTS part to simplify.

Code:
# Redirect to https
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect to www
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteRule (.*) https://www.yourdomain.com/$1 [E=HTTPS,R=301,L]

# Security header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
Google's tool tipped me off that they want to see two redirects not one. The env=HTTPS environment variable wasn't working as expected. So I used the E=HTTPS flag on the www redirect to set the env=HTTPS environment variable on the next request.

Apache 2.4 Env Docs
Environment Variables in Apache - Apache HTTP Server Version 2.4

Test with these two:
HSTS Preload List Submission (Google)
Analyse your HTTP response headers

If anyone wants to add to this or confirm the fix feel free. I doubt I'm the only one having trouble with this.
This my htaccess but still this site check giving error. Error: No HSTS header and Error: HTTP redirects to www first. Please let me know this fix, Thanks

Code:
RewriteEngine On

# Force www:
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Force SSL:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Security header Enable HSTS
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS

What is correct rules for Enable HSTS ?

Code:
Header set Strict-Transport-Security "max-age=31536000" env=HTTPS

or

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS

or

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" preload env=HTTPS
 
Last edited:
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
Error: No HSTS header and Error: HTTP redirects to www first.
I see that you quoted my working rules but your example doesn't follow them. The HSTS test error says that you redirected www first, your first rule is "Force www". And you also did not set the E=HTTPS flag.

Try to copy and paste the three rules I created to replace yours. Change "yourdomain" of course. Do not change the order of the rules. Do not combine them with other rules or conditions. You can add rules below these three lines as needed.
 

Nirjonadda

Well-Known Member
May 8, 2013
762
28
78
cPanel Access Level
Root Administrator
I see that you quoted my working rules but your example doesn't follow them. The HSTS test error says that you redirected www first, your first rule is "Force www". And you also did not set the E=HTTPS flag.

Try to copy and paste the three rules I created to replace yours. Change "yourdomain" of course. Do not change the order of the rules. Do not combine them with other rules or conditions. You can add rules below these three lines as needed.
So is this correct rules? Please let me know.

Code:
RewriteEngine On

# Force www:
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [E=HTTPS,R=301,L]

# Force SSL:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Security header Enable HSTS
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
 
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator
So is this correct rules?
Not correct. You changed the order of the rules. Here is my code copy from above in the chain:

Code:
# Redirect to https
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect to www
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteRule (.*) https://www.yourdomain.com/$1 [E=HTTPS,R=301,L]

# Security header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
I would suggest that you hard code the domain name as I have shown in the example also.
 
  • Like
Reactions: Nirjonadda

Nirjonadda

Well-Known Member
May 8, 2013
762
28
78
cPanel Access Level
Root Administrator
Not correct. You changed the order of the rules. Here is my code copy from above in the chain:

Code:
# Redirect to https
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect to www
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteRule (.*) https://www.yourdomain.com/$1 [E=HTTPS,R=301,L]

# Security header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
I would suggest that you hard code the domain name as I have shown in the example also.
One more ask, How to work HSTS preload?
 
Mar 17, 2016
18
1
3
cPanel Access Level
Root Administrator

Nirjonadda

Well-Known Member
May 8, 2013
762
28
78
cPanel Access Level
Root Administrator
Please start a new thread if you want advice on preload. My advice is simply DO NOT PRELOAD.
I am suggesting that you pass the test up to the point you only get the preload error.

Also review your headers in your browser F12 dev tools.
Thanks for your great support, Now all are working without any issue.

Code:
RewriteEngine On

# Force SSL:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Force www:
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [E=HTTPS,R=301,L]

# Security header Enable HSTS
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
 
  • Like
Reactions: John Napoletano

Rajeeva Lochana

Well-Known Member
Community Guide Contributor
May 27, 2019
122
39
28
India
cPanel Access Level
Root Administrator
Thanks so much for all the replies for this thread, it helped me a lot.

I myself use this and I suggest this for HSTS:
For me using this, HSTS doesn't work on the normal https without subdomain. It is wierd.
Code:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
So I use:
Code:
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"
I think this is a better idea. But it is always up to you.