Nginx安全優化與效能調優

itbsl發表於2020-07-25

Nginx基本安全優化

隱藏Nginx軟體版本號資訊

一般來說,軟體的漏洞都和版本有關,這個很像汽車的缺陷,同一批次的要有問題就都有問題,別的批次可能就都是好的。因此,我們應儘量隱藏或者消除Web服務對訪問使用者顯示各類敏感資訊(例如Web軟體名稱以及版本號等資訊),增加惡意使用者攻擊伺服器的難度,從而加強Web伺服器的安全性。

我現在在我的CentOS7上編譯安裝了Nginx,當我們請求伺服器的時候我們可以通過chrome的除錯工具看到我們請求的伺服器Nginx的版本,如下圖所示

假如Nginx1.18.0這個版本有漏洞,那麼惡意使用者就可以根據這個資訊通過漏洞來攻擊我們的伺服器

現在我們來在Nginx的配置檔案nginx.conf中增加一項引數來隱藏Nginx的版本,這樣使用者就不知道我們用的是哪個版本的Nginx了。

在nginx.conf中的http標籤段內加入server_tokens off;引數,如下圖所示

現在我們重啟伺服器再次訪問可以看到Nginx版本號已經看不到了

更改原始碼隱藏Nginx軟體名及版本號

隱藏了Nginx版本號後,更進一步,可以通過一些手段把Web服務軟體的名稱也隱藏起來,或者改為其他Web服務軟體名以迷惑惡意使用者。Nginx並不提供修改Nginx軟體名稱的引數和入口,需要修改原始碼才行,這裡只是提供一個思路,修改原始碼需慎重,防止修改原始碼導致伺服器不能正常執行。其它伺服器軟體同理。修改方法自行百度。

修改Nginx服務的預設使用者

為了讓Web服務更安全,要儘可能地改掉軟體預設的配置,比如埠、使用者等。

下面就來更改Ninx服務的預設使用者。

首先,檢視Ninx服務對應的預設使用者。一般情況下,Ninx服務啟動後,預設使用的使用者是nobody,檢視預設的配置檔案命令如下:

grep '#user' nginx.conf.default

為了防止黑客猜到這個Web服務的使用者,我們需要更改為特殊的使用者名稱,例如www、nginx或者特殊點的itbsl,但是這個使用者必須是系統裡事先存在的,下面以nginx使用者為例進行說明

(1)為Nginx服務建立新使用者

為Nginx服務建立新使用者的操作過程如下:

useradd nginx -s /sbin/nologin -M # 不需要有系統登入許可權,應當禁止其登入能力

(2)配置Nginx服務,讓其使用剛建立的Nginx使用者

更改Nginx服務預設使用的使用者,方法有兩種

第一種是直接修改配置檔案引數,將預設的#user nobody;修改為如下內容:

user nginx nginx;

如果註釋或不設定上述引數,預設為nobody使用者,不推薦使用nobody使用者名稱,最好採用一個普通使用者。

第二種方法為直接在編譯Nginx軟體的時候指定編譯的使用者名稱和組,命令如下(推薦使用該種方式):

./configure \
--user=nginx \
--group=nginx \
--prefix=/usr/local/nginx-1.18.0 \
--with-http_v2_module \
--with-http_ssl_module \
--with-http_stub_status_module

提示:在編譯Nginx服務時,直接指定使用者和組,這樣無論配置檔案中是否加引數,預設都是nginx使用者。

修改引數優化Nginx服務效能

優化Nginx服務的worker程式數

在高併發、高訪問量的Web服務場景,需要事先啟動好更多的Nginx程式,以保證快速響應並處理大量併發使用者的請求。

1.優化NGINX程式對應的配置

優化Nginx程式對應的Nginx服務的配置引數如下:

worker_processes  1; # 指定了Nginx要開啟的程式數,結尾的數字就是程式的個數

上述引數調整的是Nginx服務的worker程式數,Nginx有Master程式和worker程式之分,Master為管理程式,真正處理請求的是worker程式。

2.優化Nginx程式個數的策略

worker_processes引數大小的設定最好和網站的使用者數量相關聯,可如果是新配置,不知道網站的使用者數量該怎麼辦?

搭建伺服器時,worker程式數最開始的設定可以等於CPU的核數,且worker程式數要多一些,這樣起始提供服務時就不會出現因為訪問量快速增加而臨時啟動新程式提供服務的問題,縮短了系統的瞬時開銷和提供服務的時間,提升了服務使用者的速度。高流量高併發場合也可以考慮將程式數提高至CPU核數*2,具體情況要根據實際的業務來選擇,因為這個引數除了要和CPU核數匹配外,也和硬碟儲存的資料及系統的負載有關,設定為CPU的核數是一個好的起始配置,這也是官方的建議。

3.檢視Web伺服器CPU硬體資源資訊

通過/proc/cpuinfo可檢視CPU個數及總核數。檢視PCU總核數的示例如下:

# 方法一
grep processor /proc/cpuinfo | wc -l
# 方法二
grep -c processor /proc/cpuinfo

通過top命令,然後按數字1,即可顯示所有的CPU核數,如下:

4.修改伺服器Nginx配置

我的伺服器時1核2G,假設伺服器的CPU顆數為1顆,核數為4核,我們將引數值改為4

worker_processes  4;

修改並儲存後,優雅重啟Nginx,使修改生效,如下:

nginx -s reload

現在檢查修改後的worker程式數量,如下:

# 假如Nginx監聽的是8埠
lsof -i:80
# 或者通過如下命令檢視
ps -ef | grep nginx | grep -v grep

worker_process可知,worker的程式數為4個。Nginx Master主程式不包含在這個引數裡,Nginx Master的主程式為管理程式,負責排程和管理worker程式。

繫結不同的Nginx程式到不同的CPU上

預設情況下,Nginx的多個程式有可能跑在某一個CPU或CPU的某一核上,導致Nginx程式使用硬體的資源不均,所以我們需要配置Nginx與CPU的親和力引數,儘可能地分配不同的Nginx程式給不同的CPU處理,打到充分有效利用硬體的多CPU多核資源的目的。

在優化不同的Nginx程式對應不同的CPU配置時,四核CPU伺服器的引數配置參考如下:

worker_processes  4;
# worker_cpu_affinity就是配置Nginx程式與CPU親和力的引數,即把不同的程式分給不同的CPU處理。這裡0001 0010 0100 1000
# 是掩碼,分別代表第1、2、3、4核CPU,由於worker_processes程式數為4,因此,該配置會吧每個程式分配一核CPU處理,預設情況
# 下程式不會繫結任何CPU,引數位置為main段
worker_cpu_affinity 0001 0010 0100 1000;

八核CPU伺服器的引數配置參考如下:

worker_processes  8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

Nginx事件處理模型優化

Nginx的連線連線處理機制在不同的作業系統會採用不同的I/O模型,在Linux下,Nginx使用epoll的I/O多路複用模型,在Freebsd中使用kqueue的I/O多路複用模型,在Solaris中使用/dev/poll方式的I/O多路複用模型,在Windows中使用的是icop,等等。

要根據系統型別選擇不同的事件處理模型,可供使用的選擇有use [kqueue|rtsig|epoll|/dev/poll|select|poll]。我使用的是CentOS7,因此將Nginx的時間處理模型調整為epoll模型。

具體的配置引數如下:

# events指令是設定Nginx的工作模式及連線數上限
events {
    use epoll;
    worker_connections  10240;
}
# use是一個事件模組指令,用來指定Nginx的工作模式。Nginx支援的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll
# 其中select和poll都是標準的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平臺上,kqueue用在BSD系統中。對於Linux系統Linux2.6+的核心,推薦選擇epoll工作模式,這是高效能高併發的設定

調整Nginx單程式允許的客戶端最大連線數

接下來,調整Nginx單個程式允許的客戶端最大連線數,這個控制連線數的引數為worker_connections

events {
    # worker_connections也是個事件模組指令,用於定義Nginx每個程式的最大連線數,預設是1024。最大客戶端連線數由
    # worker_processes和worker_connections決定,即Max_client=worker_processes*worker_connections。程式
    # 的最大連線數受Linux系統程式的最大開啟檔案數限制,在執行作業系統命令`ulimit -HSn 65535`或配置相關檔案後,
    # worker_connections的設定才能生效
    worker_connections  10240;
}

說明:worker_connections用來設定一個worker process支援的最大併發連線數,這個連線數包括了所有連線,例如:代理伺服器的連線、客戶端的連線等,實際的併發連線數除了受worker_connections引數控制外,還和最大開啟檔案數 worker_rlimit_nofile有關,Nginx總併發連線=worker數量 * worker_connections。

配置Nginx worker程式最大開啟檔案數

接下來,調整配置Nginx worker程式的最大開啟檔案數,這個控制連線數的引數為worker_rlimit_nofile。該引數的實際配置如下:

# 最大開啟檔案數,可設定為系統優化後的ulimit -HSn的結果,調整系統檔案描述和這個問題有相同之處
worker_rlimit_nofile 65535;

開啟高效檔案傳輸模式

1.設定引數: sendfile on;

sendfile引數用於開啟檔案的高效傳輸模式。同時將tcp_nopush和tcp_nodelay兩個指令設定為on,可防止網路及磁碟I/O阻塞,提升Nginx工作效率。

sendfile    on;

2.設定引數:tcp_nopush on;

引數作用:啟用或禁用

限制檔案上傳大小

下面介紹如何調整上傳檔案的大小(http Request body size)限制。

在nginx.conf的http段增加如下配置引數:

client_max_body_size 10m; # 最大允許上傳的檔案大小根據業務需求來設定

如果上傳的檔案大小超過該設定,那麼就會報413 Request Entity Too Large的錯誤。

配置gzip壓縮實現效能優化

Nginx gzip壓縮功能介紹

Nginx gzip壓縮模組提供了壓縮檔案內容的功能,使用者請求的內容在傳送到使用者客戶端之前,Nginx伺服器會根據一些具體的策略實施壓縮策略,以節約網站出口頻寬,同時加快資料傳輸效率,來提升使用者訪問體驗。

Nginx gzip壓縮的優點

  • 提升網站使用者體驗:傳送給使用者的內容小了,使用者訪問單位大小的頁面就加快了,使用者體驗提升了,網站口碑就好了
  • 節約網站頻寬成本:資料是壓縮傳輸的,因此節省了網站的頻寬流量成本,不過壓縮時會稍微消耗一些CPU資源,這個一般可以忽略不計

需要和不需要壓縮的物件

  • 純文字內容壓縮比很高,因此,純文字的內容最好進行壓縮,例如:html、css、js、xml、shtml等格式的檔案
  • 被壓縮的純文字檔案必須大於1KB,由於壓縮演算法的特殊原因,極小的檔案壓縮後可能反而變大
  • 圖片、視訊(流媒體)等檔案儘量不要壓縮,因為這些檔案大多都是經過壓縮的,如果再壓縮很可能不會減小或減小很少,或者可能增大,同事壓縮時還會消耗大量的CPU、記憶體資源

引數介紹及配置使用

此壓縮功能與早期的Apache服務的mod_deflate壓縮功能很相似,Nginx的gzip壓縮功能依賴於ngx_http_gzip_module模組,預設已安裝。

對應的壓縮引數說明如下:

#壓縮配置
# 開啟gzip壓縮功能
gzip on;  
# 設定允許壓縮的頁面最小位元組數,頁面位元組數從header頭的Content-Length中獲取。預設值是0,表示不管頁面多大都進行壓縮。
# 建議設定成大於1K,如果小於1K可能會越壓越大
gzip_min_length 1k; 
# 壓縮快取區大小。表示申請4個單位的位16K的記憶體作為壓縮結果流快取,
# 預設值是申請與原始資料大小相同的記憶體空間來儲存gizp壓縮結構
gzip_buffers 4 16k;
# 壓縮版本(預設1.1),用於設定識別HTTP協議版本,預設是1.1,目前大部分瀏覽器都支援GZIP解壓,使用預設即可
gzip_http_version 1.1;
# 壓縮比率。用來指定gzip壓縮比,1壓縮比最小,處理速度最快;9壓縮比最大,傳輸速度快,但處理最慢,也比較消耗CPU資源
gzip_comp_level 2;
# 用來指定壓縮的型別
gzip_types text/plain text/css text/xml application/javascript;
# vary header支援。該選項可以讓前端的快取伺服器快取經過gzip壓縮的頁面,例如用Squid快取經過Nginx壓縮的資料
gzip_vary on;

不同Nginx版本中,gzip_types的配置可能會有不同,對應的檔案型別,請檢視安裝目錄的mime.types檔案

增加http accept-ranges頭來提高效能

網頁的圖片,js ,css ,視訊 都加 http accept-ranges頭,以支援多執行緒載入,斷點續傳,提高效能!目前各大網站都在使用此方式!

server {
  listen 80;
  server_name p2hp.com;
  location ~ ^/(img/|js/|css/|upload/|font/|fonts/|res/|video) {
    add_header Access-Control-Allow-Origin *;
    add_header Accept-Ranges bytes;
    root /var/www/...;
    access_log off;
    expires 30d;
  }
}

Nginx日誌相關優化與安全

Nginx access日誌切割

為什麼要做日誌切割?

因為隨時系統訪問量的增長,訪問日誌裡會出現越來越多的資料,如果不去按照時間去做合理的日誌切割,訪問日誌裡的資料多到無法開啟的地步,所以需要做日誌切割。

建立一個runlog.sh檔案,按天切割

LOGPATH=/usr/local/nginx/logs/access.log
BASEPATH=/usr/local/nginx/logs/access/$(date -d yesterday +%Y%m)

mkdir -p $BASEPATH

BACKUP=$BASEPATH/$(date -d yesterday +%Y%m%d).access.log

mv $LOGPATH $BACKUP
touch $LOGPATH
/usr/local/nginx/sbin/nginx -s reopen

然後配合定時任務,每天零點切割一次

0 0 * * * sh /usr/local/nginx/logs/runlog.sh

Nginx圖片及目錄防盜鏈解決方案

如果我們自己網站內的圖片資源被其它網站所盜用,這會增加自己網站的頻寬資源,增加很多額外的消耗,而且會對我們系統的穩定性有影響,為了防止自己網站上的圖片資源被其它網站所盜用,我們需要給自己的伺服器配置防盜鏈。

在Nginx的配置檔案nginx.conf的 server段匹配圖片資源允許的域名,,不匹配的直接重定向到其它連線或者直接返回403錯誤。

# 圖片防盜鏈
location ~* \.(png|jpg|jpeg|gif|swf|flv)$ {
    valid_referers none blocked www.test.com *.test.com;
    if ($invalid_referer) {
        # 如果有盜鏈的情況就使用url重寫到錯誤頁面(示例重定向到了百度首頁logo圖片)
        rewrite ^/ https://www.baidu.com/img/bd_logo1.png?qua=high;
        # 或者直接返回403錯誤碼
        #return 403;
    }
}

Nginx防爬蟲優化

robots.txt機器人協議介紹

Robots協議(也稱為爬蟲協議、機器人協議等)的全稱是“網路爬蟲排除標準”(Robots Exclusion Protocol),網站通過Robots協議告訴搜尋引擎那些頁面可以抓取,那些頁面不能抓取。

Nginx防爬蟲優化配置

我們可以根據客戶端的user-agent資訊,輕鬆地阻止指定的爬蟲爬取我們的網站。下面來看幾個案例。

範例1:阻止下載協議代理,命令如下:

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

說明:如果使用者匹配了if後面的客戶端(例如wget),就返回403

範例2:測試禁止不同的瀏覽器軟體訪問

示例程式碼如下:

if ($http_user_agent ~* "Firefox|MSIE") {
    rewrite ^(.*) http://www.baidu.com/$1 permanent;
}

如果瀏覽器為FireFox或IE,就會跳轉到http://www.baidu.com。

相關文章