• Openresty通过Lua+Redis 实现动态封禁IP


    求背景

    为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单。对于黑名单之内的 IP ,拒绝提供服务。并且可以设置失效

    1.安装Openresty(编译安装)

    1. wget https://openresty.org/download/openresty-1.19.3.1.tar.gz
    2. # 解压openresty
    3. tar -zxvf openresty-1.19.3.1.tar.gz

    下载缓存插件
     

    1. wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
    2. #解压缓存插件
    3. tar -zxvf ngx_cache_purge-2.3.tar.gz
    4. cd openresty-1.19.3.1/
    5. mkdir modules
    6. # 把刚解压的ngx_cache_purge移动到该目录下

    安装依赖

    yum install pcre-devel openssl-devel gcc curl -y

    编译OpenResty

    选择需要的插件启用, –with-Components 激活组件,–without 则是禁止组件 ,–add-module是安装第三方模块。
    进入刚刚解压好的openresty-1.19.3.1根目录下执行命令

    ./configure --prefix=/usr/local/openresty --with-luajit --without-http_redis2_module --with-http_stub_status_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --add-module=/usr/local/openresty-1.19.3.1/modules/ngx_cache_purge-2.3 
    

    –prefix=/usr/local/openresty: 刚自己创建的目录,用来存放编译后的openresty
    –add-module=/usr/local/openresty-1.19.3.1/xxx: 存放第三方插件的位置

    2.安装redis

    这里我是基于docker安装的redis 

    docker run --restart=always -p 6379:6379 --name myredis -d redis:7.0.12  --requirepass xxx
    

    - -requirepass 是redis密码

    3.写lua脚本

    1. ip_bind_time = 30 --封禁IP多长时间
    2. ip_time_out = 6 --指定统计ip访问频率时间范围
    3. connect_count = 10 --指定ip访问频率计数最大值
    4. --上面的意思就是6秒内访问超过10次,自动封 IP 30秒。
    5. --连接redis
    6. local redis = require "resty.redis"
    7. local cache = redis.new()
    8. local ok , err = cache.connect(cache,"127.0.0.1","6379")
    9. -- redis密码
    10. local res, err = cache:auth("xxx")
    11. cache:set_timeout(60000)
    12. --如果连接失败,跳转到脚本结尾
    13. if not ok then
    14. goto Lastend
    15. end
    16. --查询ip是否在封禁段内,若在则返回403错误代码
    17. --因封禁时间会大于ip记录时间,故此处不对ip时间key和计数key做处理
    18. is_bind , err = cache:get("bind_"..ngx.var.remote_addr)
    19. if is_bind == '1' then
    20. ngx.exit(ngx.HTTP_FORBIDDEN)
    21. -- 或者 ngx.exit(403)
    22. -- 当然,你也可以返回500错误啥的,搞一个500页面,提示,亲您访问太频繁啥的。
    23. goto Lastend
    24. end
    25. start_time , err = cache:get("time_"..ngx.var.remote_addr)
    26. ip_count , err = cache:get("count_"..ngx.var.remote_addr)
    27. --如果ip记录时间大于指定时间间隔或者记录时间或者不存在ip时间key则重置时间key和计数key
    28. --如果ip时间key小于时间间隔,则ip计数+1,且如果ip计数大于ip频率计数,则设置ip的封禁key为1
    29. --同时设置封禁key的过期时间为封禁ip的时间
    30. if start_time == ngx.null or os.time() - start_time > ip_time_out then
    31. res , err = cache:set("time_"..ngx.var.remote_addr , os.time())
    32. res , err = cache:set("count_"..ngx.var.remote_addr , 1)
    33. else
    34. ip_count = ip_count + 1
    35. res , err = cache:incr("count_"..ngx.var.remote_addr)
    36. if ip_count >= connect_count then
    37. res , err = cache:set("bind_"..ngx.var.remote_addr,1)
    38. res , err = cache:expire("bind_"..ngx.var.remote_addr,ip_bind_time) --fix keys
    39. end
    40. end
    41. --结尾标记
    42. ::Lastend::
    43. local ok, err = cache:close()
    1. #user nobody;
    2. worker_processes 1;
    3. #error_log logs/error.log;
    4. #error_log logs/error.log notice;
    5. #error_log logs/error.log info;
    6. #pid logs/nginx.pid;
    7. events {
    8. worker_connections 1024;
    9. }
    10. http {
    11. include mime.types;
    12. default_type application/octet-stream;
    13. #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    14. # '$status $body_bytes_sent "$http_referer" '
    15. # '"$http_user_agent" "$http_x_forwarded_for"';
    16. #access_log logs/access.log main;
    17. sendfile on;
    18. #tcp_nopush on;
    19. #keepalive_timeout 0;
    20. keepalive_timeout 65;
    21. #gzip on;
    22. server {
    23. listen 80;
    24. server_name localhost;
    25. #charset koi8-r;
    26. #access_log logs/host.access.log main;
    27. location / {
    28. root html;
    29. index index.html index.htm;
    30. access_by_lua_file "/usr/local/openresty/nginx/lua/access_by_redis.lua";
    31. }
    32. #error_page 404 /404.html;
    33. # redirect server error pages to the static page /50x.html
    34. #
    35. error_page 500 502 503 504 /50x.html;
    36. location = /50x.html {
    37. root html;
    38. }
    39. # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    40. #
    41. #location ~ \.php$ {
    42. # proxy_pass http://127.0.0.1;
    43. #}
    44. # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    45. #
    46. #location ~ \.php$ {
    47. # root html;
    48. # fastcgi_pass 127.0.0.1:9000;
    49. # fastcgi_index index.php;
    50. # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
    51. # include fastcgi_params;
    52. #}
    53. # deny access to .htaccess files, if Apache's document root
    54. # concurs with nginx's one
    55. #
    56. #location ~ /\.ht {
    57. # deny all;
    58. #}
    59. }
    60. # another virtual host using mix of IP-, name-, and port-based configuration
    61. #
    62. #server {
    63. # listen 8000;
    64. # listen somename:8080;
    65. # server_name somename alias another.alias;
    66. # location / {
    67. # root html;
    68. # index index.html index.htm;
    69. # }
    70. #}
    71. # HTTPS server
    72. #
    73. #server {
    74. # listen 443 ssl;
    75. # server_name localhost;
    76. # ssl_certificate cert.pem;
    77. # ssl_certificate_key cert.key;
    78. # ssl_session_cache shared:SSL:1m;
    79. # ssl_session_timeout 5m;
    80. # ssl_ciphers HIGH:!aNULL:!MD5;
    81. # ssl_prefer_server_ciphers on;
    82. # location / {
    83. # root html;
    84. # index index.html index.htm;
    85. # }
    86. #}
    87. }

    启动下就可以了

  • 相关阅读:
    计算机毕业设计Java无人售货机管理系统(源码+系统+mysql数据库+Lw文档)
    使用ansible统一管理修改Linux和Windows管理员密码
    【redis】Stream、String 超详细介绍
    CSP认证202305-2矩阵运算(c++)
    linux uname详解 -s -r -a 查看内核版本
    【牛客网】二叉树遍历(八)
    用递归函数遍历判断同一层级某个属性值是否相同
    数据探测之扫号攻击
    【Spring】spring中存储Bean(对象)的相关注解及相关用法
    【软件测试】功能测试/接口测试/自动化测试/性能测试/验收测试
  • 原文地址:https://blog.csdn.net/cjj2006/article/details/133434550