无需操作,在上一个实验《容器化应用的动态发布实验手册》中已经完成此操作。
使用chrome浏览器访问 https://udf.f5.com/ ,选择 Invited Users:
一切就绪后,您可以点击课程右端的launch 启动您的课程,您将进入课程文档的界面。
打开Lab Guide中的链接:https://gitee.com/michaelwang19/0917_NGINX_OSS_Security
该文档详细说明了实验操作步骤。 您也可以点击DEPLOYMENT打开部署环境,您将看到环境正在被拉起,耐心等待,直到各组件前出现绿色三角,表明环境就绪:
接下来,您就可以通过Web Shell或者SSH客户端访问NGINX Security:
下载RDP远程桌面配置:
远程桌面登录Client客户端,账号密码为:
账号:Administrator
密码:gUyLsoBjoUjaD
Web Shell或SSH登录NGINX Security虚拟机之后,首先确认一下NGINX的运行状态是active (running) :
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# systemctl status nginx
● nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2022-08-31 11:58:03 UTC; 3h 52min ago
Docs: http://nginx.org/en/docs/
Process: 1898 ExecStop=/usr/local/nginx/sbin/nginx -s quit (code=exited, status=0/SUCCESS)
Process: 1902 ExecStart=/usr/local/nginx/sbin/nginx (code=exited, status=0/SUCCESS)
Main PID: 1903 (nginx)
CGroup: /system.slice/nginx.service
├─1903 nginx: master process /usr/local/nginx/sbin/nginx
└─2272 nginx: worker process
为方便不同技术栈背景的学员的学习,降低实验环境带来的时间消耗,将实验环境简化。
并对实验涉及到的配置全部编写在配置文件中,通过配置文件中添加注释和取消注释的方式做不同的实验。
每次NGINX配置修改后请执行配置文件校验是否存在错误:
[centos@2370ed03-0df5-471a-bc80-3928ece95a4c ~]$ sudo su
[root@2370ed03-0df5-471a-bc80-3928ece95a4c centos]# cd /usr/local/nginx/sbin
[root@2370ed03-0df5-471a-bc80-3928ece95a4c 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
提示successful之后,执行NGINX配置重新加载指令:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# ./nginx -s reload
本实验小节,NGINX通过限制客户端Client的IP地址10.1.1.6的访问,但是同网段10.1.1.0/24其他IP允许访问。
修改NGINX配置:
[centos@2370ed03-0df5-471a-bc80-3928ece95a4c ~]$ sudo su
[root@2370ed03-0df5-471a-bc80-3928ece95a4c centos]# cd /usr/local/nginx/sbin
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# vim /usr/local/nginx/conf/nginx.conf
将以下两行deny 10.1.1.6和allow 10.1.1.0/24前面的注释符#去掉,并保存配置。
server {
listen 80;
server_name www.example.com;
#charset koi8-r;
access_log logs/host.access.log main;
error_log logs/error.log info;
#deny 10.1.1.6;
#allow 10.1.1.0/24;
验证配置是否有错误:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c 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
提示successful之后,执行NGINX配置重新加载指令:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# ./nginx -s reload
使用Client客户端(10.1.1.6)访问NGINX的服务(10.1.1.5:80):
curl http://10.1.1.5
拦截效果:
检查日志:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# tail -f /usr/local/nginx/logs/error.log
2022/09/02 18:17:49 [notice] 1671#0: signal process started
2022/09/02 18:21:01 [notice] 1676#0: signal process started
2022/09/02 18:29:25 [notice] 1680#0: signal process started
2022/09/02 22:50:56 [notice] 2028#0: signal process started
2022/09/03 08:36:35 [emerg] 1414#0: unknown "accessip" variable
2022/09/03 08:44:57 [notice] 1509#0: signal process started
2022/09/03 08:50:39 [error] 1510#0: *4 access forbidden by rule, client: 10.1.1.6, server: www.example.com, request: "GET / HTTP/1.1", host: "10.1.1.5"
2022/09/03 08:50:39 [info] 1510#0: *4 client 10.1.1.6 closed keepalive connection
2022/09/03 08:51:45 [error] 1510#0: *5 access forbidden by rule, client: 10.1.1.6, server: www.example.com, request: "GET / HTTP/1.1", host: "10.1.1.5"
2022/09/03 08:51:46 [error] 1510#0: *5 access forbidden by rule, client: 10.1.1.6, server: www.example.com, request: "GET /favicon.ico HTTP/1.1", host: "10.1.1.5", referrer: "http://10.1.1.5/"
日志截图如下:
本实验小节,由于实验环境是纯内网环境,无法通过互联网直接访问NGINX,因此,NGINX上检测到的IP地址都是内网IP。
而且真实应用场景中,NGINX多数部署在内网,数据包在进入NGINX的时候,前段会存在多次的IP地址转换NAT的设备,因此,实际应用场景中,NGINX在网络数据包层面看到的多数也是内网IP地址。这就是为什么实际应用场景中,NGINX上经常会启用一些技术手段来获取真实的客户端IP地址,比较常用的就是通过X-Forwarded-For字段来传递真实客户端IP。
为了验证该实验效果,我们通过在HTTP包头中插入标准的X-Forwarded-For字段,来模拟真实环境中NGINX通过限制客户端IP所属的地域属性。
实验中用到的两个IP分别为:
可以通过以下网站查询IP的地域信息:
https://www.maxmind.com/en/geoip2-precision-demo
修改NGINX配置:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# vim /usr/local/nginx/conf/nginx.conf
将以下4行geoip开头和map这部分配置前面的注释符#去掉,参考如下:
http {
include mime.types;
default_type application/octet-stream;
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoIPCity.dat;
geoip_proxy 10.1.1.6;
geoip_proxy_recursive on;
map $geoip_country_code $accessip {
default false;
US false;
CN true;
}
将上一个实验《IP地址限制》中两行deny 10.1.1.6和allow 10.1.1.0/24注释掉。 并将下面的if语句和proxy_set_header前面的注释取消,参考如下。
server {
listen 80;
server_name www.example.com;
#charset koi8-r;
access_log logs/host.access.log main;
error_log logs/error.log info;
# deny 10.1.1.6;
# allow 10.1.1.0/24;
if ( $accessip = 'false') {return 403;}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
验证配置是否有错误:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c 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
提示successful之后,执行NGINX配置重新加载指令:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# ./nginx -s reload
使用Client客户端(10.1.1.6)访问NGINX的服务(10.1.1.5:80):
curl -H "X-Forwarded-For:202.96.209.5" http://10.1.1.5
可以看到允许正常访问:
检查日志:
curl -H "X-Forwarded-For:8.8.8.8" http://10.1.1.5
可以看到访问被拦截,返回403:
检查日志:
恢复环境:
参照以下将对应的配置注释掉:
http {
include mime.types;
default_type application/octet-stream;
#geoip_country /usr/share/GeoIP/GeoIP.dat;
#geoip_city /usr/share/GeoIP/GeoIPCity.dat;
#geoip_proxy 10.1.1.6;
#geoip_proxy_recursive on;
#map $geoip_country_code $accessip {
# default false;
# US false;
# CN true;
#}
server {
listen 80;
server_name www.example.com;
#charset koi8-r;
access_log logs/host.access.log main;
error_log logs/error.log info;
#deny 10.1.1.6;
#allow 10.1.1.0/24;
# if ( $accessip = 'false') {return 403;}
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
删除log格式中2个变量geoip_country_code和accessip的调用,即保留如下:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
在上一个实验《容器化应用的动态发布实验手册》的第5个实验中,已经了解到通过KIC实现连接数限制的方法。 本实验小节,通过NGINX来实现连接数的限制。
修改NGINX配置:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# vim /usr/local/nginx/conf/nginx.conf
将以下limit_conn_zone $remote_addr zone=ip:10m前面的注释符#去掉:
http {
include mime.types;
default_type application/octet-stream;
# geoip_country /usr/share/GeoIP/GeoIP.dat;
# geoip_city /usr/share/GeoIP/GeoIPCity.dat;
# geoip_proxy 10.1.1.6;
# geoip_proxy_recursive on;
# map $geoip_country_code $accessip {
# default false;
# US false;
# CN true;
# }
limit_conn_zone $remote_addr zone=ip:10m;
#limit_req_zone $remote_addr zone=reqzone:10m rate=2r/m;
将以下limit_conn_status, limit_rate, limit_conn_log_level, limit_conn ip这4个配置前面的注释符取消掉:
说明: 由于实验环境是内网,而且NGINX高性能的处理效率,所以为了验证连接数限制的效果,通过limit_rate参数将每秒返回50个字节的数据量,将限制的并发连接数调小。 实际环境中的应用,根据实际情况设置连接数。
配置如下:
location /limit {
root html;
index limit_conn.html;
#proxy_pass http://127.0.0.1/limit/;
# limit_except GET {
# deny all;
# }
#This is limit connection section
limit_conn_status 509;
limit_rate 50;
limit_conn_log_level warn;
limit_conn ip 1;
验证配置是否有错误,提示successful之后,执行NGINX配置重新加载指令。
使用Client开启2个命令行工具,发送curl验证连接数限制:
curl -I http://10.1.1.5/limit/
可以看到超过1个连接之后,第二个连接请求被返回在配置中定义好的509状态码:
检查日志,看到请求被连接数限制:
本实验小节,通过对每秒或者每分钟的请求速率进行限制。 限制基于源IP来限制请求速率,每分钟请求不能超过2次,突发请求缓冲3个,超出3个缓冲连接后即返回503响应码。
修改NGINX配置:
将http配置块中的limit_req_zonet这部分注释取消,参考如下配置:
http {
include mime.types;
default_type application/octet-stream;
# geoip_country /usr/share/GeoIP/GeoIP.dat;
# geoip_city /usr/share/GeoIP/GeoIPCity.dat;
# geoip_proxy 10.1.1.6;
# geoip_proxy_recursive on;
# map $geoip_country_code $accessip {
# default false;
# US false;
# CN true;
# }
limit_conn_zone $remote_addr zone=ip:10m;
limit_req_zone $remote_addr zone=reqzone:10m rate=2r/m;
将location配置块中的This is limit request section后面4行配置的注释取消,参考如下配置:
location /limit {
root html;
index limit_conn.html;
#proxy_pass http://127.0.0.1/limit/;
# limit_except GET {
# deny all;
# }
#This is limit connection section
limit_conn_status 509;
limit_rate 50;
limit_conn_log_level warn;
limit_conn ip 1;
#This is limit request section
limit_req zone=reqzone;
limit_req zone=reqzone burst=3 nodelay;
limit_conn_status 503;
limit_conn_log_level warn;
}
使用Client客户端测试:
curl -I http://10.1.1.5/limit/
测试效果:
检查log日志:
可以看到日志中显示是请求request超过了限制。
本实验小节,通过对HTTP请求方式Method进行限制,如POST、GET、HEAD、PUT、PATCH、OPTIONS、DELETE、CONNECT、TRACE。 如针对不同的uri只允许指定的GET方法使用,其他的方法都拒绝。
修改NGINX配置:
将limit_except这3行配置注释取消,参考如下配置:
location /limit {
root html;
index limit_conn.html;
#proxy_pass http://127.0.0.1/limit/;
limit_except GET {
deny all;
}
使用Client客户端测试:
curl -X POST http://10.1.1.5/limit/
测试效果:
检查log日志:
可以看到日志中显示POST方法不被允许使用,返回了405响应码。
本章节涉及的证书已经通过openssl自签发,用于临时测试使用,所以证书属于浏览器不受信任的证书,在测试过程中看到浏览器报证书不受信的提示时,可以忽略。
修改配置,https配置部分加载证书和key,其他配置采用NGINX默认,不作额外修改:
server {
listen 443 ssl;
server_name www.test.com;
ssl_certificate /usr/local/nginx/conf/www.test.com.crt;
ssl_certificate_key /usr/local/nginx/conf/www.test.com.key;
location / {
root html;
index index.html index.htm;
客户端Client访问:
https://www.test.com
检查证书信息:
检查所支持的SSL/TLS相关算法:
修改配置,增加TLSv1.3协议的支持:
取消ssl_protocol前面的注释,参考如下:
#HTTPS Server
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /usr/local/nginx/conf/www.example.com.crt;
ssl_certificate_key /usr/local/nginx/conf/www.example.com.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
#ssl_ciphers ALL:!IDEA;
# ssl_ciphers HIGH;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
客户端Client浏览器访问:
https://www.example.com
检查证书信息:
使用客户端Client桌面上Zenmap软件测试算法支持情况:
nmap -sV -p 443 --script ssl-enum-ciphers www.example.com
检查所支持的SSL/TLS相关算法,扫描发现TLSv1.3算法:
修改配置,调整当前NGINX版本中所有SSL算法支持:
取消ssl_protocol前面的注释,参考如下:
#HTTPS Server
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /usr/local/nginx/conf/www.example.com.crt;
ssl_certificate_key /usr/local/nginx/conf/www.example.com.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ALL;
#ssl_ciphers ALL:!IDEA;
# ssl_ciphers HIGH;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
使用客户端Client桌面上Zenmap软件测试算法支持情况:
nmap -sV -p 443 --script ssl-enum-ciphers www.example.com
检查所支持的SSL/TLS相关算法,扫描发现存在warning信息,提示IDEA算法漏洞存在SWEET32攻击风险:
禁用IDEA算法,可以通过调整算法组合,也可以直接禁用该算法,如下是直接禁用该算法的方式:
修改配置:
#HTTPS Server
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /usr/local/nginx/conf/www.example.com.crt;
ssl_certificate_key /usr/local/nginx/conf/www.example.com.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
# ssl_ciphers ALL;
ssl_ciphers ALL:!IDEA;
# ssl_ciphers HIGH;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
保存配置,并加载配置。
再次使用Zenmap软件测试算法支持情况:
发现已经无法扫描出IDEA算法:
本实验小节,通过在http的服务中启用301重定向的策略,将http的请求强制跳转至https的请求,来实现强制加密访问的需求。
修改配置文件,在80服务中启用强制HTTPS跳转访问的策略:
server {
listen 80;
server_name www.example.com;
#charset koi8-r;
access_log logs/host.access.log main;
error_log logs/error.log info;
#deny 10.1.1.6;
#allow 10.1.1.0/24;
# if ( $accessip = 'false') {return 403;}
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#limit_conn_status 509;
#limit_conn_log_level warn;
#limit_rate 50;
#limit_conn ip 1;
return 301 https://$server_name$request_uri;
保存配置,并加载配置。
客户端Client使用Chrome浏览器,并开发者工具,访问:
http://www.example.com
可以看到http请求被301重定向访问至https
恢复环境:
修改配置,将强制https跳转的配置注释:
server {
listen 80;
server_name www.example.com;
#charset koi8-r;
access_log logs/host.access.log main;
error_log logs/error.log info;
#deny 10.1.1.6;
#allow 10.1.1.0/24;
# if ( $accessip = 'false') {return 403;}
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#limit_conn_status 509;
#limit_conn_log_level warn;
#limit_rate 50;
#limit_conn ip 1;
#return 301 https://$server_name$request_uri;
本实验小节,用来验证实际应用场景中,会存在不同的域名,但是提供的服务是相同的。所以就需要在同一个IP中启用不同的域名的证书。
确认以下2个443监听端口的配置中,分别挂载了2套不同的证书:
#HTTPS Server
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /usr/local/nginx/conf/www.example.com.crt;
ssl_certificate_key /usr/local/nginx/conf/www.example.com.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
#ssl_ciphers ALL;
ssl_ciphers ALL:!IDEA;
# ssl_ciphers HIGH;
# ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root html;
index index.html index.htm;
}
}
server {
listen 443 ssl;
server_name www.test.com;
ssl_certificate /usr/local/nginx/conf/www.test.com.crt;
ssl_certificate_key /usr/local/nginx/conf/www.test.com.key;
location / {
root html;
index index.html index.htm;
}
}
保存配置,并加载配置。
客户端Client使用Chrome浏览器,分别访问2个域名:
https://www.example.com
https://www.test.com
检查每个域名对应的加载的证书信息:
本实验小节,通过NGINX对访问请求做基本的用户名密码认证。
检查配置,参考如下:
location /login {
auth_basic "Login Auth";
auth_basic_user_file /usr/local/nginx/conf/plain_pass;
root html;
index login_auth.html;
}
其中,用户名密码文件已经提前通过htpasswd命令生成好,放在/usr/local/nginx/conf/plain_pass文件中,如下格式:
[root@2370ed03-0df5-471a-bc80-3928ece95a4c sbin]# cat /usr/local/nginx/conf/plain_pass
#plain password
#test:password123
test:$apr1$eWZ.7ICp$a533nPfihwalfGANpy6oE/
客户端Client使用Chrome浏览器,访问测试:
http://www.example.com/login/
弹出用户名密码认证窗口:
登录成功后,页面提示:
如果输入用户名密码错误,无法登录:
检查log日志信息:
恭喜您已经完成本次培训的所有实验内容! Cheers!
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。