前 25 个 Nginx Web 服务器最佳安全实践
N ginx 是一款轻量级、高性能的 Web 服务器/反向代理和电子邮件 (IMAP/POP3) 代理。它可在 UNIX、GNU/Linux、BSD 变体、Mac OS X、Solaris 和 Microsoft Windows 上运行。据 Netcraft 称,互联网上 13.50% 的域使用 nginx Web 服务器。Nginx 是为解决 C10K 问题而编写的少数服务器之一。与传统服务器不同,Nginx 不依赖线程来处理请求。相反,它使用更具可扩展性的事件驱动(异步)架构。Nginx 为多个高流量网站提供支持,例如 WordPress、Hulu、Github 和 SourceForge。
本页收集有关如何提高在 Linux 或类 UNIX 操作系统上运行的 nginx Web 服务器的安全性的提示。
教程详细信息 | |
---|---|
难度等级 | 简单的 |
Root 权限 | 是的 |
要求 | Linux 或 Unix 终端 |
类别 | Web 服务器 |
操作系统兼容性 | AIX • Alma • Alpine • Arch • BSD • Debian • Fedora • FreeBSD • HP-UX • Linux • macOS • Mint • NetBSD • OpenBSD • openSUSE • Pop!_OS • RHEL • Rocky • Stream • SUSE • Ubuntu • Unix • WSL |
预计阅读时间 | 20 分钟 |
默认配置文件和 Nginx 端口
- /usr/local/nginx/conf/或者/etc/nginx/– nginx 服务器配置目录和 /usr/local/nginx/conf/nginx.conf 是主配置文件。
- /usr/local/nginx/html/或/var/www/html– 默认文档位置。
- /usr/local/nginx/logs/或/var/log/nginx– 默认日志文件位置。
- Nginx HTTP 默认端口:TCP 80
- Nginx HTTPS 默认端口:TCP 443
您可以按如下方式测试 nginx 配置更改:
# /usr/local/nginx/sbin/nginx -t
或
# nginx -t
示例输出:
the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok configuration file /usr/local/nginx/conf/nginx.conf test is successful
要加载配置更改,请键入:
# /usr/local/nginx/sbin/nginx -s reload
或
# nginx -s reload
要停止服务器,请键入:
# /usr/local/nginx/sbin/nginx -s stop
或
# nginx -s stop
#1:打开 SELinux
安全增强型 Linux (SELinux) 是一项 Linux 内核功能,它提供了一种支持访问控制安全策略的机制,从而提供了强大的保护。它可以在系统被 root 之前阻止许多攻击。了解如何为基于 CentOS / RHEL的系统启用SELinux 。
执行布尔锁定
运行 getsebool -a 命令和锁定系统:
getsebool -a | less getsebool -a | grep off getsebool -a | grep on
为了确保机器的安全,请查看设置为“开”的设置,如果这些设置不适用于您的设置,则使用 setsebool 命令将其更改为“关”。设置正确的 SE Linux 布尔值以保持功能和保护。请注意,SELinux 会为典型的 RHEL 或 CentOS 安装增加 2-8% 的开销。
#2:通过挂载选项允许最小权限
通过单独的分区为所有网页 / html / php 文件提供服务。例如,创建一个名为 /dev/sda5 的分区并挂载在 /nginx 上。确保 /nginx 以noexec、nodev 和 nosetuid权限挂载。这是我用于挂载 /nginx 的 /etc/fstab 条目:
LABEL=/nginx /nginx ext3 defaults,nosuid,noexec,nodev 1 2
请注意,您需要使用fdisk 和 mkfs.ext3命令创建一个新的分区。
#3:Linux /etc/sysctl.conf 强化
您可以通过/etc/sysctl.conf控制和配置 Linux 内核和网络设置。
# Avoid a smurf attack net.ipv4.icmp_echo_ignore_broadcasts = 1 # Turn on protection for bad icmp error messages net.ipv4.icmp_ignore_bogus_error_responses = 1 # Turn on syncookies for SYN flood attack protection net.ipv4.tcp_syncookies = 1 # Turn on and log spoofed, source routed, and redirect packets net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians = 1 # No source routed packets here net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 # Turn on reverse path filtering net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 # Make sure no one can alter the routing tables net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0 # Don't act as a router net.ipv4.ip_forward = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 # Turn on execshild kernel.exec-shield = 1 kernel.randomize_va_space = 1 # Tuen IPv6 net.ipv6.conf.default.router_solicitations = 0 net.ipv6.conf.default.accept_ra_rtr_pref = 0 net.ipv6.conf.default.accept_ra_pinfo = 0 net.ipv6.conf.default.accept_ra_defrtr = 0 net.ipv6.conf.default.autoconf = 0 net.ipv6.conf.default.dad_transmits = 0 net.ipv6.conf.default.max_addresses = 1 # Optimization for port usefor LBs # Increase system file descriptor limit fs.file-max = 65535 # Allow for more PIDs (to reduce rollover problems); may break some programs 32768 kernel.pid_max = 65536 # Increase system IP port limits net.ipv4.ip_local_port_range = 2000 65000 # Increase TCP max buffer size setable using setsockopt() net.ipv4.tcp_rmem = 4096 87380 8388608 net.ipv4.tcp_wmem = 4096 87380 8388608 # Increase Linux auto tuning TCP buffer limits # min, default, and max number of bytes to use # set max to at least 4MB, or higher if you use very high BDP paths # Tcp Windows etc net.core.rmem_max = 8388608 net.core.wmem_max = 8388608 net.core.netdev_max_backlog = 5000 net.ipv4.tcp_window_scaling = 1
参见:
- Linux 调优 VM(内存)子系统
- Linux 调整网络堆栈(缓冲区大小)以提高网络性能
#4:删除所有不需要的 Nginx 模块
您需要尽量减少直接编译到 nginx 二进制文件中的模块数量。通过限制 Web 服务器允许的功能,可以最大程度地降低风险。您可以仅使用必需的模块来配置和安装 nginx。例如,禁用 SSI 和 autoindex 模块,您可以键入:
键入以下命令以查看在编译 nginx 服务器时可以打开或关闭哪些模块:
禁用不需要的 nginx 模块。
# ./configure --without-http_autoindex_module --without-http_ssi_module
# make
# make install
# ./configure --help | less
(可选)更改 Nginx 版本标头
编辑src/http/ngx_http_header_filter_module.c,输入:
# vi +48 src/http/ngx_http_header_filter_module.c
查找行
static char ngx_http_server_string[] = "Server: nginx" CRLF; static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
更改如下:
static char ngx_http_server_string[] = "Server: Ninja Web Server" CRLF; static char ngx_http_server_full_string[] = "Server: Ninja Web Server" CRLF;
保存并关闭文件。现在,您可以编译服务器。在 nginx.conf 中添加以下内容以关闭所有自动生成的错误页面上显示的 nginx 版本号:
server_tokens off;
请参阅如何在 Linux 和 Unix 上隐藏 Nginx 版本以了解其他可能的配置选项。
#5:使用 mod_security(仅适用于后端 Apache 服务器)
mod_security 为 Apache 提供应用程序级防火墙。为所有后端Apache Web 服务器安装 mod_security。这将阻止许多注入攻击。
#6:安装 SELinux 策略来强化 Nginx Web 服务器
默认情况下,SELinux 不会保护 nginx Web 服务器。但是,您可以按如下方式安装和编译保护。首先,安装所需的 SELinux 编译时支持:从项目
# yum -y install selinux-policy-targeted selinux-policy-devel
主页
下载有针对性的 SELinux 策略以强化 Linux 服务器上的 nginx Web 服务器:
解压相同的文件:
编译相同的
文件示例输出:
# cd /opt
# wget 'http://downloads.sourceforge.net/project/selinuxnginx/se-ngix_1_0_10.tar.gz?use_mirror=nchc'
# tar -zxvf se-ngix_1_0_10.tar.gz
# cd se-ngix_1_0_10/nginx
# make
Compiling targeted nginx module /usr/bin/checkmodule: loading policy configuration from tmp/nginx.tmp /usr/bin/checkmodule: policy configuration loaded /usr/bin/checkmodule: writing binary representation (version 6) to tmp/nginx.mod Creating targeted nginx.pp policy package rm tmp/nginx.mod.fc tmp/nginx.mod
安装生成的 nginx.pp SELinux 模块:
# /usr/sbin/semodule -i nginx.pp
#7:基于限制性 Iptables 的防火墙
以下防火墙脚本阻止所有内容并且仅允许:
- 传入 HTTP(TCP 端口 80)请求
- 传入 ICMP ping 请求
- 传出 ntp(端口 123)请求
- 传出 smtp(TCP 端口 25)请求
#!/bin/bash IPT="/sbin/iptables" #### IPS ###### # Get server public ip SERVER_IP=$(ifconfig eth0 | grep 'inet addr:' | awk -F'inet addr:' '{ print $2}' | awk '{ print $1}') LB1_IP="204.54.1.1" LB2_IP="204.54.1.2" # Do some smart logic so that we can use damm script on LB2 too OTHER_LB="" SERVER_IP="" [[ "$SERVER_IP" == "$LB1_IP" ]] && OTHER_LB="$LB2_IP" || OTHER_LB="$LB1_IP" [[ "$OTHER_LB" == "$LB2_IP" ]] && OPP_LB="$LB1_IP" || OPP_LB="$LB2_IP" ### IPs ### PUB_SSH_ONLY="122.xx.yy.zz/29" #### FILES ##### BLOCKED_IP_TDB=/root/.fw/blocked.ip.txt SPOOFIP="127.0.0.0/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 169.254.0.0/16 0.0.0.0/8 240.0.0.0/4 255.255.255.255/32 168.254.0.0/16 224.0.0.0/4 240.0.0.0/5 248.0.0.0/5 192.0.2.0/24" BADIPS=$( [[ -f ${BLOCKED_IP_TDB} ]] && grep -E -v "^#|^$" ${BLOCKED_IP_TDB}) ### Interfaces ### PUB_IF="eth0" # public interface LO_IF="lo" # loopback VPN_IF="eth1" # vpn / private net ### start firewall ### echo "Setting LB1 $(hostname) Firewall..." # DROP and close everything $IPT -P INPUT DROP $IPT -P OUTPUT DROP $IPT -P FORWARD DROP # Unlimited lo access $IPT -A INPUT -i ${LO_IF} -j ACCEPT $IPT -A OUTPUT -o ${LO_IF} -j ACCEPT # Unlimited vpn / pnet access $IPT -A INPUT -i ${VPN_IF} -j ACCEPT $IPT -A OUTPUT -o ${VPN_IF} -j ACCEPT # Drop sync $IPT -A INPUT -i ${PUB_IF} -p tcp ! --syn -m state --state NEW -j DROP # Drop Fragments $IPT -A INPUT -i ${PUB_IF} -f -j DROP $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL ALL -j DROP # Drop NULL packets $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL NONE -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " NULL Packets " $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL NONE -j DROP $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,RST SYN,RST -j DROP # Drop XMAS $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " XMAS Packets " $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP # Drop FIN packet scans $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags FIN,ACK FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " Fin Packets Scan " $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags FIN,ACK FIN -j DROP $IPT -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP # Log and get rid of broadcast / multicast and invalid $IPT -A INPUT -i ${PUB_IF} -m pkttype --pkt-type broadcast -j LOG --log-prefix " Broadcast " $IPT -A INPUT -i ${PUB_IF} -m pkttype --pkt-type broadcast -j DROP $IPT -A INPUT -i ${PUB_IF} -m pkttype --pkt-type multicast -j LOG --log-prefix " Multicast " $IPT -A INPUT -i ${PUB_IF} -m pkttype --pkt-type multicast -j DROP $IPT -A INPUT -i ${PUB_IF} -m state --state INVALID -j LOG --log-prefix " Invalid " $IPT -A INPUT -i ${PUB_IF} -m state --state INVALID -j DROP # Log and block spoofed ips $IPT -N spooflist for ipblock in $SPOOFIP do $IPT -A spooflist -i ${PUB_IF} -s $ipblock -j LOG --log-prefix " SPOOF List Block " $IPT -A spooflist -i ${PUB_IF} -s $ipblock -j DROP done $IPT -I INPUT -j spooflist $IPT -I OUTPUT -j spooflist $IPT -I FORWARD -j spooflist # Allow ssh only from selected public ips for ip in ${PUB_SSH_ONLY} do $IPT -A INPUT -i ${PUB_IF} -s ${ip} -p tcp -d ${SERVER_IP} --destination-port 22 -j ACCEPT $IPT -A OUTPUT -o ${PUB_IF} -d ${ip} -p tcp -s ${SERVER_IP} --sport 22 -j ACCEPT done # allow incoming ICMP ping pong stuff $IPT -A INPUT -i ${PUB_IF} -p icmp --icmp-type 8 -s 0/0 -m state --state NEW,ESTABLISHED,RELATED -m limit --limit 30/sec -j ACCEPT $IPT -A OUTPUT -o ${PUB_IF} -p icmp --icmp-type 0 -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT # allow incoming HTTP port 80 $IPT -A INPUT -i ${PUB_IF} -p tcp -s 0/0 --sport 1024:65535 --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT $IPT -A OUTPUT -o ${PUB_IF} -p tcp --sport 80 -d 0/0 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT # allow outgoing ntp $IPT -A OUTPUT -o ${PUB_IF} -p udp --dport 123 -m state --state NEW,ESTABLISHED -j ACCEPT $IPT -A INPUT -i ${PUB_IF} -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT # allow outgoing smtp $IPT -A OUTPUT -o ${PUB_IF} -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT $IPT -A INPUT -i ${PUB_IF} -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT ### add your other rules here #### ####################### # drop and log everything else $IPT -A INPUT -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " DEFAULT DROP " $IPT -A INPUT -j DROP exit 0
有关详细信息,请参阅以下教程:
- 如何在 Ubuntu 16.04 LTS 服务器上设置 UFW 防火墙
- CentOS / Redhat Iptables 防火墙配置教程
- Linux:面向新系统管理员的 20 个 Iptables 示例
- 另请查看ufw 命令和iptables 命令示例
#8:控制缓冲区溢出攻击
编辑 nginx.conf,设置所有客户端的缓冲区大小限制。
# vi /usr/local/nginx/conf/nginx.conf
编辑并设置所有客户端的缓冲区大小限制,如下所示:
## Start: Size Limits & Buffer Overflows ##
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
## END: Size Limits & Buffer Overflows ##
在哪里,
- client_body_buffer_size 1k – (默认为 8k 或 16k)该指令指定客户端请求主体缓冲区大小。
- client_header_buffer_size 1k – 该指令设置来自客户端的请求标头的标头缓冲区大小。对于绝大多数请求,缓冲区大小为 1K 就足够了。如果您有自定义标头或从客户端(例如 wap 客户端)发送的大型 cookie,请增加此值。
- client_max_body_size 1k – 指令指定客户端请求的最大可接受主体大小,由请求标头中的 Content-Length 行指示。如果大小大于给定值,则客户端会收到错误“请求实体太大”(413)。当您通过 POST 方法获取文件上传时,请增加此值。
- large_client_header_buffers 2 1k – 指令指定从客户端请求中读取大型标头的缓冲区的最大数量和大小。默认情况下,一个缓冲区的大小等于页面的大小,具体取决于平台,可以是 4K 或 8K,如果在工作请求结束时连接转换为保持活动状态,则释放这些缓冲区。2x1k 将接受 2kB 数据 URI。这也有助于抵御恶意机器人和 DoS 攻击。
您还需要控制超时以提高服务器性能并减少客户端。编辑如下:
## Start: Timeouts ## client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10; ## End: Timeouts ##
- client_body_timeout 10; – 该指令设置客户端请求主体的读取超时。仅当一次读取步骤中未获取主体时才设置超时。如果在此时间之后客户端未发送任何内容,则 nginx 返回错误“请求超时”(408)。默认值为 60。
- client_header_timeout 10; – Directive assigns timeout with reading of the title of the request of client. The timeout is set only if a header is not get in one readstep. If after this time the client send nothing, nginx returns error “Request time out” (408).
- keepalive_timeout 5 5; – The first parameter assigns the timeout for keep-alive connections with the client. The server will close connections after this time. The optional second parameter assigns the time value in the header Keep-Alive: timeout=time of the response. This header can convince some browsers to close the connection, so that the server does not have to. Without this parameter, nginx does not send a Keep-Alive header (though this is not what makes a connection “keep-alive”).
- send_timeout 10; – Directive assigns response timeout to client. Timeout is established not on entire transfer of answer, but only between two operations of reading, if after this time client will take nothing, then nginx is shutting down the connection.
#9: Control Simultaneous Connections
You can use NginxHttpLimitZone module to limit the number of simultaneous connections for the assigned session or as a special case, from one IP address. Edit nginx.conf:
### Directive describes the zone, in which the session states are stored i.e. store in slimits. ### ### 1m can handle 32000 sessions with 32 bytes/session, set to 5m x 32000 session ### limit_zone slimits $binary_remote_addr 5m; ### Control maximum number of simultaneous connections for one session i.e. ### ### restricts the amount of connections from a single ip address ### limit_conn slimits 5;
The above will limits remote clients to no more than 5 concurrently “open” connections per remote ip address.
#10: Allow Access To Our Domain Only
If bot is just making random server scan for all domains, just deny it. You must only allow configured virtual domain or reverse proxy requests. You don’t want to display request using an IP address:
## Only requests to our Host are allowed i.e. example.in, images.example.in and www.example.in if ($host !~ ^(example.in|www.example.in|images.example.in)$ ) { return 444; } ##
#11: Limit Available Methods
GET and POST are the most common methods on the Internet. Web server methods are defined in RFC 2616. If a web server does not require the implementation of all available methods, they should be disabled. The following will filter and only allow GET, HEAD and POST methods:
## Only allow these request methods ## if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } ## Do not accept DELETE, SEARCH and other methods ##
More About HTTP Methods
- The GET method is used to request document such as https://www.example.com/index.php.
- The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
- The POST method may involve anything, like storing or updating data, or ordering a product, or sending E-mail by submitting the form. This is usually processed using the server side scripting such as PHP, PERL, Python and so on. You must use this if you want to upload files and process forms on server.
#12: How Do I Deny Certain User-Agents?
You can easily block user-agents i.e. scanners, bots, and spammers who may be abusing your server.
## Block download agents ## if ($http_user_agent ~* LWP::Simple|BBBike|wget) { return 403; } ##
Block robots called msnbot and scrapbot:
## Block some robots ## if ($http_user_agent ~* msnbot|scrapbot) { return 403; }
#12: How Do I Block Referral Spam?
Referer spam is dengerouns. It can harm your SEO ranking via web-logs (if published) as referer field refer to their spammy site. You can block access to referer spammers with these lines.
## Deny certain Referers ### if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) ) { # return 404; return 403; } ##
#13: How Do I Stop Image Hotlinking?
Image or HTML hotlinking means someone makes a link to your site to one of your images, but displays it on their own site. The end result you will end up paying for bandwidth bills and make the content look like part of the hijacker’s site. This is usually done on forums and blogs. I strongly suggest you block and stop image hotlinking at your server level itself.
# Stop deep linking or hot linking location /images/ { valid_referers none blocked www.example.com example.com; if ($invalid_referer) { return 403; } }
Example: Rewrite And Display Image
Another example with link to banned image:
valid_referers blocked www.example.com example.com; if ($invalid_referer) { rewrite ^/images/uploads.*\.(gif|jpg|jpeg|png)$ http://www.examples.com/banned.jpg last }
See also:
- HowTo: Use nginx map to block image hotlinking. This is useful if you want to block tons of domains.
#14: Directory Restrictions
You can set access control for a specified directory. All web directories should be configured on a case-by-case basis, allowing access only where needed.
Limiting Access By Ip Address
You can limit access to directory by ip address to /docs/ directory:
location /docs/ { ## block one workstation deny 192.168.1.1; ## allow anyone in 192.168.1.0/24 allow 192.168.1.0/24; ## drop rest of the world deny all; }
Password Protect The Directory
First create the password file and add a user called vivek:
# mkdir /usr/local/nginx/conf/.htpasswd/
# htpasswd -c /usr/local/nginx/conf/.htpasswd/passwd vivek
Edit nginx.conf and protect the required directories as follows:
### Password Protect /personal-images/ and /delta/ directories ### location ~ /(personal-images/.*|delta/.*) { auth_basic "Restricted"; auth_basic_user_file /usr/local/nginx/conf/.htpasswd/passwd; }
Once a password file has been generated, subsequent users can be added with the following command:
# htpasswd -s /usr/local/nginx/conf/.htpasswd/passwd userName
#15: Nginx SSL Configuration
HTTP is a plain text protocol and it is open to passive monitoring. You should use SSL to to encrypt your content for users:
- HowTo: Create a Self-Signed SSL Certificate on Nginx For CentOS / RHEL
- How to configure Nginx with free Let’s Encrypt SSL certificate on Debian or Ubuntu Linux
- How to install Letsencrypt free SSL/TLS for Nginx certificate on Alpine Linux
- How to configure Nginx SSL/TLS passthrough with TCP load balancing
- nginx: Setup SSL Reverse Proxy (Load Balanced SSL Proxy)
#16: Nginx And PHP Security Tips
PHP is one of the popular server side scripting language. Edit /etc/php.ini as follows:
# Disallow dangerous functions disable_functions = phpinfo, system, mail, exec ## Try to limit resources ## # Maximum execution time of each script, in seconds max_execution_time = 30 # Maximum amount of time each script may spend parsing request data max_input_time = 60 # Maximum amount of memory a script may consume (8MB) memory_limit = 8M # Maximum size of POST data that PHP will accept. post_max_size = 8M # Whether to allow HTTP file uploads. file_uploads = Off # Maximum allowed size for uploaded files. upload_max_filesize = 2M # Do not expose PHP error messages to external users display_errors = Off # Turn on safe mode safe_mode = On # Only allow access to executables in isolated directory safe_mode_exec_dir = php-required-executables-path # Limit external access to PHP environment safe_mode_allowed_env_vars = PHP_ # Restrict PHP information leakage expose_php = Off # Log all errors log_errors = On # Do not register globals for input data register_globals = Off # Minimize allowable PHP post size post_max_size = 1K # Ensure PHP redirects appropriately cgi.force_redirect = 0 # Disallow uploading unless necessary file_uploads = Off # Enable SQL safe mode sql.safe_mode = On # Avoid Opening remote files allow_url_fopen = Off
See also:
- PHP Security: Limit Resources Used By Script
- PHP.INI settings: Disable exec, shell_exec, system, popen and Other Functions To Improve Security
#17: Run Nginx In A Chroot Jail (Containers) If Possible
Putting nginx in a chroot jail minimizes the damage done by a potential break-in by isolating the web server to a small section of the filesystem. You can use traditional chroot kind of setup with nginx. If possible use FreeBSD jails, XEN, Linux containers on a Debian/Ubuntu, LXD on a Fedora, or OpenVZ virtualization which uses the concept of containers.
#18: Limits Connections Per IP At The Firewall Level
A webserver must keep an eye on connections and limit connections per second. This is serving 101. Both pf and iptables can throttle end users before accessing your nginx server.
Linux Iptables: Throttle Nginx Connections Per Second
The following example will drop incoming connections if IP make more than 15 connection attempts to port 80 within 60 seconds:
/sbin/iptables -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set /sbin/iptables -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 15 -j DROP service iptables save
BSD PF: Throttle Nginx Connections Per Second
Edit your /etc/pf.conf and update it as follows. The following will limits the maximum number of connections per source to 100. 15/5 specifies the number of connections per second or span of seconds i.e. rate limit the number of connections to 15 in a 5 second span. If anyone breaks our rules add them to our abusive_ips table and block them for making any further connections. Finally, flush keyword kills all states created by the matching rule which originate from the host which exceeds these limits.
webserver_ip="202.54.1.1" table <abusive_ips> persist block in quick from <abusive_ips> pass in on $ext_if proto tcp to $webserver_ip port www flags S/SA keep state (max-src-conn 100, max-src-conn-rate 15/5, overload <abusive_ips> flush)
Please adjust all values as per your requirements and traffic (browsers may open multiple connections to your site). See also:
- Sample PF firewall script.
- Sample Iptables firewall script.
#19: Configure Operating System to Protect Web Server
Turn on SELinux as described above. Set correct permissions on /nginx document root. The nginx runs as a user named nginx. However, the files in the DocumentRoot (/nginx or /usr/local/nginx/html) should not be owned or writable by that user. To find files with wrong permissions, use:
# find /nginx -user nginx
# find /usr/local/nginx/html -user nginx
Make sure you change file ownership to root or other user. A typical set of permission /usr/local/nginx/html/
# ls -l /usr/local/nginx/html/
Sample outputs:
-rw-r--r-- 1 root root 925 Jan 3 00:50 error4xx.html -rw-r--r-- 1 root root 52 Jan 3 10:00 error5xx.html -rw-r--r-- 1 root root 134 Jan 3 00:52 index.html
You must delete unwated backup files created by vi or other text editor:
# find /nginx -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'
# find /usr/local/nginx/html/ -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'
Pass -delete option to find command and it will get rid of those files too.
#20: Restrict Outgoing Nginx Connections
The crackers will download file locally on your server using tools such as wget. Use iptables to block outgoing connections from nginx user. The ipt_owner module attempts to match various characteristics of the packet creator, for locally generated packets. It is only valid in the OUTPUT chain. In this example, allow vivek user to connect outside using port 80 (useful for RHN access or to grab CentOS updates via repos):
/sbin/iptables -A OUTPUT -o eth0 -m owner --uid-owner vivek -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
Add above rule to your iptables based shell script. Do not allow nginx web server user to connect outside.
#21: Keep your software up to date
You must keep your software and kernel up to date all time. Apply patch as per your version or distro. If you are using a Debian/Ubuntu Linux use apt-get command/apt command to apply patches:
$ sudo apt-get update
$ sudo apt-get upgrade
If you are using a RHEL/CentOS/Oracle/Scientific Linux, use yum command:
$ sudo yum update
If you are using an Alpine Linux use apk command:
# apk update
# apk upgrade
#22 : Avoid clickjacking
Add the following in your nginx.conf or virtual domain to avoid clickjacking:
add_header X-Frame-Options SAMEORIGIN;
#23 : Disable content-type sniffing on some browsers
Add the following in your nginx.conf or virtual domain:
add_header X-Content-Type-Options nosniff;
#23 : Enable the Cross-site scripting (XSS) filter
Add the following in your nginx.conf or virtual domain:
add_header X-XSS-Protection "1; mode=block";
#24: Force HTTPS
There is no reason to use HTTP. Force everyone to use HTTPS by deault:
- How To: Nginx Redirect All HTTP Request To HTTPS Rewrite 301 Rules
- How to redirect non-www to www HTTP / TLS /SSL traffic on Nginx
#25: Monitoring nginx
Stub Status 允许查看客户端请求总数和其他信息。查看如何启用它以获取更多信息:
退回提示:查看日志和审计
检查日志文件。它们将让您了解针对服务器的攻击,并允许您检查是否存在必要的安全级别。例如:
最好使用 logroate 命令定期轮换日志,并使用df 命令/du 命令密切关注磁盘空间,以避免 DoS 攻击:
auditd 服务用于系统审计。将其打开以审计服务SELinux 事件、身份验证事件、文件修改、帐户修改等。像往常一样禁用所有服务并遵循我们的“Linux 服务器强化”安全提示。
# grep "/login.php??" /usr/local/nginx/logs/access_log
# grep "...etc/passwd" /usr/local/nginx/logs/access_log
# grep -E -i "denied|error|warn" /usr/local/nginx/logs/error_log
# df -h
# du -chs /var/www/html/
结论
您的 nginx 服务器现已正确加固并准备好为网页提供服务。但是,您应该咨询更多资源以满足您的 Web 应用程序安全需求。例如,wordpress 或任何其他第三方应用程序都有自己的安全要求。
参考:
- 20 个 Linux 服务器强化安全技巧
- 如何:在 keepalived 的帮助下设置nginx 反向代理和 HA 集群。
- nginx wiki——官方 nginx wiki。
- OpenBSD 特定的Nginx 安装和安全性如何。