一些网站的通用安全建议

自从半年前在Google Cloud的VPS因为开放了wordpress的REST API而导致被(似乎是韩国人)劫持的经历后,就开始重视服务器安全了。后来陆续读了不少关于wp安全的文章,发现很多安全建议都是通用的,很容易generalize到其他系统的实践中,但是这篇文章并不会详细到某个命令的操作,也不打算讨论诸如使用cloudflare这种企业方案。经常听说chmod 777 is evil,却很少有人主动给出一些权限方案的建议,那什么样的权限是好的权限呢?我也经常在思考这个问题,猜测如果严格推导这个问题少不了动用set theory甚至category theory来做,所以这里并不打算深究一些形式上很漂亮的solution,而是写下我这几年实践和从别处学来总结的一点准则。 这里的建议分为三个level,一是操作系统级,二是应用服务器级,三是应用级,这篇文章主要是focus通用建议,所以关于这三个level的建议应该也是顺序递减的。这篇文章也会持续的更新。

操作系统级

文件权限

这部分思考网站目录下的文件归属和读写执行权限到底应该如何分配,建议如下:

1. 除网站应用built-in功能需要写的目录和文件的组设置为web-server执行用户组外,网站根目录及所有子目录、文件的归属和归属组都设置为管理用户(非超级用户)及其组。例如我的HaiChienTeng,wp程序有个built-in的主题编辑器需要对/wp-content/themes/目录下的文件进行写操作,所以将这个目录及其下的文件的归属用户设置为HaiChienTeng,归属组设置为apache

2. 除网站应用built-in功能需要写的目录权限设775,文件设664外,所有目录的权限设置为755,所有文件的权限设置为644。使得黑客即使获得web-server执行用户的权限也不能对其他目录和文件进行写操作

3. 配置文件和应用分离,配置文件放在网站目录外,并配置归属用户为管理用户,归属组为web-server执行用户组,权限为440,仅管理用户和web-server执行用户组可执行也仅可执行读操作

4. 创建一个特定的用户,使用systemctl以该用户启动web-server。例如建立一个apache或者nobody这样的用户,不分配shell,限制该用户的命令权限等,不要用root启动

网络权限

1. 使用非默认端口。例如使用38022代替22端口

2. 使用安全的连接方式。例如SSH禁止PasswordAuthentication,仅使用PubkeyAuthentication登录

3. 使用iptables最小化开放端口,例如仅允许38022(SSH),80(HTTP),443(HTTPS)端口开放,其他端口的包一律drop

4. 只在本地使用的服务要避免监听外网连接,确保不需要外网连接的服务不用listen 0.0.0.0,只接受本地连接,典型场景是MySQL和redis,即使需要开启外网连接监听也要尽量开启iptables白名单功能。例如我的Tencent Cloud的MySQL需要给另一台机器A提供服务,所以MySQL端口仅仅允许A的公网IP请求连接,其他IP的连接请求一律建议drop

 应用服务器级

1. 仅允许用户使用HTTPS连接网站。例如使用Let's Encrypt

2. 使用应用服务器端转发功能防止对敏感文件的访问。例如使用apache的rewriteRule

3. 使用应用服务器的安全拓展。例如apache的mod_security和mod_evasive,配置OWASP

应用级

1. 使用应用内的权限机制来控制登录。例如设置MySQL的root用户仅接受特定IP的登录

2. 使用开源应用的时候不要使用默认表前缀

待续

references:
[1] Hardening WordPress
[2] Protect Apache Against Brute Force or DDoS Attacks Using Mod_Security and Mod_evasive Modules