Category Archives: security

wordpress file owner and permission with nginx on Centos 7 (SElinux on)

As a security tool, SElinux is great. Howere, it gives me nightmares when I setup a wordpress sites with nginx.

File owner and permission setup:

  • I set the owner of all wordpress files as MY_USER_NAME
  • I add MY_USER_NAME to nginx group
  • I set all wordpress files to group-readable and group-writable, (so that nginx can read and write)
sudo usermod -a -G nginx MY_USER_NAME

sudo chown -R MY_USER_NAME:nginx *

sudo find . -type d -exec chmod 775 {} \;
sudo find . -type f -exec chmod 664 {} \;

Problem 1: cannot upload media file
Problem 2: cannot install plugin (wordpress asks for FTP)

Fix 1:

chcon -t httpd_sys_rw_content_t html

maybe: 
sudo chcon --reference=html example.com
sudo chcon --reference=html example.com/html

When I check SElinux log with:

sudo sealert -a /var/log/audit/audit.log

I find SElinux prevents nginx/php-fpm write example.com/html.

But I did not get any warning when I start nginx. As I remember, starting Apache without this fix will fail?

Fix 2:

sudo chown -R nginx wp-content
sudo chown -R nginx wp-admin

maybe:
sudo chcon --reference=../html wp-content

I though changing the owner of wp-content should be enough, but no, it does not work. I have to change the owner of wp-admin as well.

On Fedora 25:
selinux blocks php-fpm for access of mysql port, to enable this access:

setsebool -P httpd_can_network_connect_db 1

For memcache:

setsebool -P httpd_can_network_memcache 1

More details are HERE.

Google Compute Engine (GCE) firewall and iptables at VM host

After I click “Allow HTTP” and “Allow HTTPS” in the settings of Centos 7 vm, I can get http or https pages of my site. What? I thought I need to explicitly allow port 80 and port 443 in iptables like I did in other servers. Why don’t I need to touch iptables in this case?

sudo iptables -L -n | less

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
INPUT_direct  all  --  0.0.0.0/0            0.0.0.0/0           
INPUT_ZONES_SOURCE  all  --  0.0.0.0/0            0.0.0.0/0           
INPUT_ZONES  all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0            ctstate INVALID
REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
...
Chain INPUT_ZONES (1 references)
target     prot opt source               destination         
IN_trusted  all  --  0.0.0.0/0            0.0.0.0/0           
IN_trusted  all  --  0.0.0.0/0            0.0.0.0/0 
...
Chain IN_trusted (2 references)
target     prot opt source               destination         
IN_trusted_log  all  --  0.0.0.0/0            0.0.0.0/0           
IN_trusted_deny  all  --  0.0.0.0/0            0.0.0.0/0           
IN_trusted_allow  all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0    
...

The last line “ACCEPT all” does not look right to me. In Chain IN_trusted, iptables does IN_trusted_{log,deny,allow} and “ACCEPT all” for the rest. Should it DROP all the others by default for security?

(Since GCE has its own firewall and it blocks all except for things allowed, “ACCEPT all” here in iptables probably won’t bring any security issues.)

When I delete the last rule, I cannot get access to my sites by port 80.

[X ~]$ sudo iptables -L IN_trusted --line-numbers

Chain IN_trusted (2 references)
num  target     prot opt source               destination         
1    IN_trusted_log  all  --  anywhere             anywhere            
2    IN_trusted_deny  all  --  anywhere             anywhere            
3    IN_trusted_allow  all  --  anywhere             anywhere            
4    ACCEPT     all  --  anywhere             anywhere

[X ~]$ sudo iptables -D IN_trusted 4
[X ~]$ sudo iptables -L IN_trusted --line-numbers

Chain IN_trusted (2 references)
num  target     prot opt source               destination         
1    IN_trusted_log  all  --  anywhere             anywhere            
2    IN_trusted_deny  all  --  anywhere             anywhere            
3    IN_trusted_allow  all  --  anywhere             anywhere 

I checked other server images, in Fedora 25 server edition:

Chain FWDI_FedoraServer (2 references)
target     prot opt source               destination         
FWDI_FedoraServer_log  all  --  0.0.0.0/0            0.0.0.0/0           
FWDI_FedoraServer_deny  all  --  0.0.0.0/0            0.0.0.0/0           
FWDI_FedoraServer_allow  all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0 

It only accepts icmp for the rests, which make much more sense to me.

Use Let’s Encrypt to Create Certificates

Let’s Encrypt is a Certificate Authority (CA) and provides FREE certificates. As of 2017/05/29, the official tool to get a certificate with shell access is Certbot.

It’s great that certbot provides convenient plugins to install and certificates for command web server software, such as apache and nginx.

However, I would prefer to NOT let any other program to touch server process and configuration. So I choose  --manual.

sudo certbot certonly --manual --preferred-challenges dns -d www.xyz.com,xyz.com

This works but renewing cert is a problem because of --manual.

An alternative way it to use --webroot when generating the certificates:

sudo certbot certonly --rsa-key-size 4096 --webroot -w /var/www/example/ -d www.example.com,example.com

Set up a cron job for renewing the certificates:

0 3,15 * * * certbot renew --quiet --no-self-upgrade --webroot && apachectl graceful