基於IP的訪問控制,基於Nginx的http_access_module模塊,是Nginx本身內置的模塊,不需要安裝的時候配置。也就是允許哪些IP訪問,不允許哪些IP訪問
server { listen 80; server_name example.com; access_log logs/access.log main; location / { deny 192.168.1.1; allow 192.168.1.0/24; allow 10.1.1.0/16; allow 2001:0db8::/32; deny all; #從上到下的順序,類似iptables。匹配到了便跳出。如上的例子先禁止了192.16.1.1,接下來允許了3個網段,其中包含了一個ipv6,最后未匹配的IP全部禁止訪問.被deny的將返回403狀態碼。 } location ~ ^/phpmyadmin/ { allow 192.168.1.0/24; deny all; #只允許局域網訪問 } location /project { allow 220.178.25.22; allow 172.2.2.0/24; allow 192.2.2.0/24; deny all; proxy_pass http://172.2.2.20:8080/project/;
proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; } #以上配置的作用是允許IP為220.178.25.22,以及172和192網段的機器可以訪問這個location地址,其他IP的客戶端訪問均是403。其中,24是指子網掩碼為255.255.255.0。 }
Nginx基於access_module有局限性
原理:基於客戶端的IP,但是對於Nginx來說,它不會管你哪個是真正的客戶端,如果我們的訪問不是客戶端與服務端直接連接,而是通過了一層代理,比如它的代理可以負載均衡、CDN的這種代理實現,也就是我們的訪問不是客戶端直接訪問的服務端,而是通過其他的中間件訪問服務端,這時候會出現一個問題,因為Nginx的access_module它是基於remote_addr這個變量來識別客戶端的IP的,那么如果一個ip通過中間件訪問服務端,那么Nginx認為訪問的ip就是中間件的IP,那么我們在基於IP做限制的時候,那么其實是沒有作用的。所以這樣的話,准確性是不高的,所以就是利用nginx的access_module有局限性。
解決方法:
①:采用別的http頭信息訪問控制,如HTTP_X_FORWARDED_FOR。
但是http_x_forwarded_for進行訪問控制會存在問題,因為是一個協議要求的,並不是所有的cdn和代理廠商它會按照要求來做,甚至x_forwarded_for存在被修改的可能,因為只是一個頭信息,所以最終還是不真實。
http_x_forwardded_for也是Nginx的http頭變量的一個常用的變量,它和remote_addr是有區別的。不同的是,x_forwarded_for是http協議中規定頭中要攜帶的,所以在客戶端訪問中間件,再訪問服務端的時候,那么服務端通過Nginx會記錄真實IP和中間件的IP。
格式:http_x_forwarded_for = 客戶端ip,第一台代理ip,第二台代理ip,第N台代理ip....,所以http_x_forwarded_for是由一連串以逗號分隔的ip組成的。
②:結合geo模塊
③:通過HTTP自定義變量傳遞
因為nginx有自己的變量,我們可以在http頭信息定義一個我們規定的http變量在所有上一級的設備手動把remote_addr的ip一級一級的攜帶過去,既能避免x_forwarded_for被修改,也能讀到客戶端的真實ip
記得修改完配置一定要檢測Nginx配置是否正確,正確后再重新軟加載配置文件
[root@~]# /usr/local/nginx/sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@~]# /usr/local/nginx/sbin/nginx -s reload