程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> Linux服務器下nginx的安全配置,linux服務器nginx

Linux服務器下nginx的安全配置,linux服務器nginx

編輯:關於PHP編程

Linux服務器下nginx的安全配置,linux服務器nginx


1、一些常識

  • linux下,要讀取一個文件,首先需要具有對文件所在文件夾的執行權限,然後需要對文件的讀取權限。

  • php文件的執行不需要文件的執行權限,只需要nginx和php-fpm運行賬戶的讀取權限。

  • 上傳木馬後,能不能列出一個文件夾的內容,跟php-fpm的運行賬戶對文件夾的讀取權限有關,木馬執行命令的權限跟php-fpm的賬戶權限有關。

  • 如果木馬要執行命令,需要php-fpm的賬戶對相應的sh有執行權限。

  • 讀取一個文件夾內的文件,是不需要對文件夾有讀取權限的,只需要對文件夾有執行權限。

1、頂部配置

#定義 Nginx 運行的用戶和用戶組
user nginx;

#進程文件
pid /var/run/nginx.pid;

#錯誤日志位置和級別,debug、info、notice、warn、error、crit
error_log  /var/log/nginx/error.log warn;

#Nginx worker 的進程數,一般可設置為可用的CPU內核數。
worker_processes 8;

#每個 worker 打開文件描述符的最大數量限制。理論值應該是最多打開文件數(系統的值ulimit -n)與 nginx 進程數相除,但是 nginx 分配請求並不均勻,所以建議與ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

2、Events 模塊

events {
    #設置一個worker進程同時打開的最大連接數
    worker_connections 2048;

    #告訴nginx收到一個新連接通知後接受盡可能多的連接
    multi_accept on;

    #設置用於復用客戶端線程的輪詢方法。如果你使用Linux 2.6+,你應該使用epoll。如果你使用*BSD,你應該使用kqueue。
    use epoll;
}

3、HTTP 模塊

http {
    #隱藏 Nginx 的版本號,提高安全性。
    server_tokens off;

    #開啟高效文件傳輸模式,sendfile 指令指定 Nginx 是否調用sendfile 函數來輸出文件,對於普通應用設為 on,如果用來進行下載等應用磁盤 IO 重負載應用,可設置為 off,以平衡磁盤與網絡 I/O 處理速度,降低系統的負載。
    sendfile on;

    #是否開啟目錄列表訪問,默認關閉。
    autoindex off;

    #告訴 Nginx 在一個數據包裡發送所有頭文件,而不一個接一個的發送
    tcp_nopush on;

    #告訴 Nginx 不要緩存數據,而是一段一段的發送--當需要及時發送數據時,就應該給應用設置這個屬性,這樣發送一小塊數據信息時就不能立即得到返回值。Nginx 默認會始終工作在 tcp nopush 狀態下。但是當開啟前面的 sendfile on; 時,它的工作特點是 nopush 的最後一個包會自動轉轉換到 nopush off。為了減小那200ms的延遲,開啟 nodelay on; 將其很快傳送出去。結論就是 sendfile on; 開啟時,tcp_nopush 和 tcp_nodelay 都是on 是可以的。
    tcp_nodelay on;

    #日志格式設定
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
    #定義訪問日志,設置為 off 可以關閉日志,提高性能
    access_log /var/log/nginx/access.log main;


    #連接超時時間,單位是秒
    keepalive_timeout 120;

    #讀取HTTP頭部的超時時間,默認值 60。客戶端與服務器建立連接後將開始接收HTTP頭部,在這個過程中,如果在一個時間間隔(超時時間)內沒有讀取到客戶端發來的字節,則認為超時,並向客戶端返回408 ("Request timed out")響應。
    client_header_timeout 60;

    #默認值 60。與client_header_timeout相似,只是這個超時時間只在讀取HTTP包體時才有效。
    client_body_timeout 10;

    #發送響應的超時時間,默認值 60。即Nginx服務器向客戶端發送了數據包,但客戶端一直沒有去接收這個數據包。如果某個連接超過send_timeout定義的超時時間,那麼Nginx將會關閉這個連接。
    send_timeout 60;

    #連接超時後將通過向客戶端發送RST包來直接重置連接。這個選項打開後,Nginx會在某個連接超時後,不是使用正常情形下的四次握手關閉TCP連接,而是直接向用戶發送RST重置包,不再等待用戶的應答,直接釋放Nginx服務器上關於這個套接字使用的所有緩存(如TCP滑動窗口)。相比正常的關閉方式,它使得服務器避免產生許多處於FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT狀態的TCP連接。注意,使用RST重置包關閉連接會帶來一些問題,默認情況下不會開啟。
    reset_timedout_connection off;

    #要限制連接,必須先有一個容器對連接進行計數,"zone=" 是給它一個名字,可以隨便叫,這個名字要跟下面的 limit_conn 一致。$binary_remote_addr 用二進制來儲存客戶端的地址,1m 可以儲存 32000 個並發會話。
    limit_conn_zone $binary_remote_addr zone=addr:5m;

    #給定的key設置最大連接數。這裡key是addr,我們設置的值是100,也就是說我們允許每一個IP地址最多同時打開有100個連接。
    limit_conn addr 100;

    #對每個連接限速100k。這如果一個IP允許兩個並發連接,那麼這個IP就是限速200K。
    limit_rate 100k; 

    #include 是一個在當前文件中包含另一個文件內容的指令。這裡我們使用它來加載文件擴展名與文件類型映射表。nginx根據映射關系,設置http請求響應頭的Content-Type值。當在映射表找不到時,使用nginx.conf中default-type指定的默認值。
    include /etc/nginx/mime.types;

    #設置文件使用的默認的MIME-type
    default_type text/html;

    #默認編碼
    charset UTF-8;

    #該模塊可以讀取預先壓縮的gz文件,這樣可以減少每次請求進行gzip壓縮的CPU資源消耗。該模塊啟用後,nginx首先檢查是否存在請求靜態文件的gz結尾的文件,如果有則直接返回該gz文件內容。
    gzip_static off;  

    #開啟 gzip 壓縮。
    gzip on;

    # 禁用客戶端為 IE6 時的 gzip功能。
    gzip_disable "msie6";

    #Nginx做為反向代理的時候啟用。可選值:off|expired|no-cache|no-sotre|private|no_last_modified|no_etag|auth|any
    gzip_proxied any;

    #設置允許壓縮的頁面最小字節數,頁面字節數從header頭中的Content-Length中進行獲取。建議設置成大於1k的字節數,小於1k可能會越壓越大。
    gzip_min_length 1024;

    #設置數據的壓縮等級。這個等級可以是1-9之間的任意數值,9是最慢但是壓縮比最大的。
    gzip_comp_level 5;

    #設置系統獲取幾個單位的緩存用於存儲gzip的壓縮結果數據流。 例如 4 4k 代表以4k為單位,按照原始數據大小以4k為單位的4倍申請內存。如果沒有設置,默認值是申請跟原始數據相同大小的內存空間去存儲gzip壓縮結果。
    gzip_buffers 4 16k;

    #設置需要壓縮的數據格式。Nginx默認只對text/html進行壓縮。
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    #為打開文件指定緩存,默認是沒有啟用的,max 指定緩存數量,建議和打開文件數一致,inactive 是指經過多長時間文件沒被請求後刪除緩存。
    open_file_cache max=65535 inactive=30s;

    #多長時間檢查一次緩存的有效信息
    open_file_cache_valid 30s;

    #open_file_cache指令中的inactive參數時間內文件的最少使用次數,如果超過這個數字,文件描述符一直是在緩存中打開的。出現 Last-Modified 不變的情況,就是因為當nginx對一個靜態文件緩存後,如果30s內還在訪問它,那麼它的緩存就一直存在,直到30s內你不訪問了為止。
    open_file_cache_min_uses 2;
    #是否記錄cache錯誤
    open_file_cache_errors on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

 4、SERVER 模塊

server {
    #監聽端口,nginx 會根據請求的 HOST 來決定使用哪個 SERVER 段的配置。如果沒有匹配的 server_name,則默認使用配置文件中第一個。加上 default_server 則可以以指定沒有匹配時的默認規則。
    #listen 80;
    listen 80 default_server;

    #域名可以有多個,用空格隔開
    server_name www.test.com test.com;
    root /user/share/nginx/html/test;

    #404頁面配置
    error_page   404   /404.html;

    #配置 ssl,有需要時開啟。
    ssl on;
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    location / {
        index   index.html index.php;
    }

    #圖片緩存時間設置
    location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
        expires 10d;
    }

    #JS和CSS緩存時間設置
    location ~ .*.(js|css)?$ {
        expires 1h;
    }

    location ~ [^/]\.php(/|$) {
        fastcgi_index   index.php;
        #開啟 PATH_INFO 支持,作用就是把參數按照給定的正則表達式分割成 $fastcgi_script_name 和 $fastcgi_path_info。
        #例如:請求 index.php/id/1 不加此行配置時,fastcgi_script_name 是 /index.php/id/1,fastcgi_path_info 是空。
        #加上之後,fastcgi_script_name 是 index.php,fastcgi_path_info 是 /id/1
        fastcgi_split_path_info ^(.+\.php)(.*)$;

        #此值即是 PHP 中 $_SERVER['SCRIPT_FILENAME'] 的值
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param   PATH_INFO               $fastcgi_path_info;
        fastcgi_param   PATH_TRANSLATED $document_root$fastcgi_path_info;

        #指定FastCGI服務器監聽端口與地址。須和 PHP-FPM 的設置相同。
        #fastcgi_pass   127.0.0.1:9000;
        fastcgi_pass    unix:/var/run/php5-fpm.sock;
        include fastcgi_params;
    }
}

2、常見的方式

1. 讓木馬上傳後不能執行:針對上傳目錄,在nginx配置文件中加入配置,使此目錄無法解析php
2. 讓木馬執行後看不到非網站目錄文件:取消php-fpm運行賬戶對於其他目錄的讀取權限
3. 木馬執行後命令不能執行:取消php-fpm賬戶對於sh的執行權限
4. 命令執行後權限不能過高:php-fpm賬戶不要用root或者加入root組

3、具體的配置

1、禁止php文件的訪問及執行

location ~  /(attachments|upload)/.*\.(php|php5)?$ { 
    deny all;
} 

2、禁止IP的訪問

//禁止的寫法
deny 10.0.0.0/24;

//允許的寫法
allow 10.0.0.0/24;  
deny all; 

3、根據用戶的真實 IP 做連接限制

## 這裡取得原始用戶的IP地址
map $http_x_forwarded_for  $clientRealIp {
	""	$remote_addr;
	~^(?P<firstAddr>[0-9\.]+),?.*$	$firstAddr;
}

## 針對原始用戶 IP 地址做限制
limit_conn_zone $clientRealIp zone=TotalConnLimitZone:20m ;
limit_conn  TotalConnLimitZone  50;
limit_conn_log_level notice;

## 針對原始用戶 IP 地址做限制
limit_req_zone $clientRealIp zone=ConnLimitZone:20m  rate=10r/s;
#limit_req zone=ConnLimitZone burst=10 nodelay;
limit_req_log_level notice;

## 具體服務器配置
server {
	listen   80;
	location ~ \.php$ {
                ## 最多 5 個排隊, 由於每秒處理 10 個請求 + 5個排隊,你一秒最多發送 15 個請求過來,再多就直接返回 503 錯誤給你了
		limit_req zone=ConnLimitZone burst=5 nodelay;

		fastcgi_pass   127.0.0.1:9000;
		fastcgi_index  index.php;
		include	fastcgi_params;
	}	

}

4、 經過多層CDN之後取得原始用戶的IP地址,nginx 配置

map $http_x_forwarded_for  $clientRealIp {
        ## 沒有通過代理,直接用 remote_addr
	""	$remote_addr;  
        ## 用正則匹配,從 x_forwarded_for 中取得用戶的原始IP
        ## 例如   X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...
        ## 這裡第一個 202.123.123.11 是用戶的真實 IP,後面其它都是經過的 CDN 服務器
	~^(?P<firstAddr>[0-9\.]+),?.*$	$firstAddr;
}

## 通過 map 指令,我們為 nginx 創建了一個變量 $clientRealIp ,這個就是 原始用戶的真實 IP 地址, 
## 不論用戶是直接訪問,還是通過一串 CDN 之後的訪問,我們都能取得正確的原始IP地址

5、隱藏版本信息

server_tokens   off;
proxy_hide_header        X-Powered-By;
//或者編譯的時候修改源代碼

6、禁用非必要的方法

if ($request_method !~ ^(GET|HEAD|POST)$ ) {
    return    444;
}

7、禁用擴展名

location ~* .(txt|doc|sql|gz|svn|git)$ {
   deny all;
}

8、合理配置響應頭

add_header  Strict-Transport-Security  "max-age=31536000";
add_header  X-Frame-Options  deny;
add_header  X-Content-Type-Options  nosniff;
add_header  Content-Security-Policy  "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://a.disquscdn.com; img-src 'self' data: https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://disqus.com";

Strict-Transport-Security(簡稱為 HSTS)可以告訴浏覽器,在指定的 max-age 內,始終通過 HTTPS 訪問

X-Frame-Options 用來指定此網頁是否允許被 iframe 嵌套,deny 就是不允許任何嵌套發生

9、拒絕一些User-Agents

if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
    return 403;
}

10、防止圖片盜鏈

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
}

11、控制緩沖區溢出攻擊

client_body_buffer_size  1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;

client_body_timeout   10;
client_header_timeout 10;
keepalive_timeout     5 5;
send_timeout          10;

解釋說明

1、client_body_buffer_size 1k-(默認8k或16k)這個指令可以指定連接請求實體的緩沖區大小。如果連接請求超過緩存區指定的值,那麼這些請求實體的整體或部分將嘗試寫入一個臨時文件。
2、client_header_buffer_size 1k-指令指定客戶端請求頭部的緩沖區大小。絕大多數情況下一個請求頭不會大於1k,不過如果有來自於wap客戶端的較大的cookie它可能會大於1k,Nginx將分配給它一個更大的緩沖區,這個值可以在large_client_header_buffers裡面設置。
3、client_max_body_size 1k-指令指定允許客戶端連接的最大請求實體大小,它出現在請求頭部的Content-Length字段。如果請求大於指定的值,客戶端將收到一個”Request Entity Too Large” (413)錯誤。記住,浏覽器並不知道怎樣顯示這個錯誤。
4、large_client_header_buffers-指定客戶端一些比較大的請求頭使用的緩沖區數量和大小。請求字段不能大於一個緩沖區大小,如果客戶端發送一個比較大的頭,nginx將返回”Request URI too large” (414)

1、client_body_timeout 10;-指令指定讀取請求實體的超時時間。這裡的超時是指一個請求實體沒有進入讀取步驟,如果連接超過這個時間而客戶端沒有任何響應,Nginx將返回一個”Request time out” (408)錯誤。
2、client_header_timeout 10;-指令指定讀取客戶端請求頭標題的超時時間。這裡的超時是指一個請求頭沒有進入讀取步驟,如果連接超過這個時間而客戶端沒有任何響應,Nginx將返回一個”Request time out” (408)錯誤。
3、keepalive_timeout 5 5; – 參數的第一個值指定了客戶端與服務器長連接的超時時間,超過這個時間,服務器將關閉連接。參數的第二個值(可選)指定了應答頭中Keep-Alive: timeout=time的time值,這個值可以使一些浏覽器知道什麼時候關閉連接,以便服務器不用重復關閉,如果不指定這個參數,nginx不會在應答頭中發送Keep-Alive信息。(但這並不是指怎樣將一個連接“Keep-Alive”)參數的這兩個值可以不相同。
4、send_timeout 10; 指令指定了發送給客戶端應答後的超時時間,Timeout是指沒有進入完整established狀態,只完成了兩次握手,如果超過這個時間客戶端沒有任何響應,nginx將關閉連接。

12、控制並發連接

limit_zone slimits $binary_remote_addr 5m;
limit_conn slimits 5;

13、sysctl.conf配置

# 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

14、在防火牆級限制每個IP的連接數

/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

15、限制Nginx連接傳出

/sbin/iptables -A OUTPUT -o eth0 -m owner --uid-owner vivek -p tcp --dport 80 -m state --state NEW,ESTABLISHED  -j ACCEPT

 

。。。

 

參考鏈接

http://www.bzfshop.net/article/176.html

http://nginx.org/en/docs/

http://www.oschina.net/translate/nginx-setup

http://www.ha97.com/5194.html

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved