kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

nginx解决sql注入

https://blog.csdn.net/A_Apprentice/article/details/125861741

  1. get请求好处理

  2. post请求 由于需要拿到请求体,需要安装lua插件支持

errlog

1
2
3
ngx.log(ngx.ERR, "error: ", body)

tail -f /var/log/nginx/error.log

当前方案 :

get在server级别处理

post在lication级别处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	# 文件上传的限制
	client_max_body_size 100m;

	if ($query_string ~* ".*('|--|union|insert|drop|truncate|update|(%20)from|grant|(%20)where|(%20)select|(%20)and|(%20)chr|(%20)mid|like|(%20)iframe|(%20)script|alert|webscan|dbappsecurity|style|WAITFOR|confirm|innerhtml|innertext|class).*") { return 403; }
        #if ($uri ~* (.*)(insert|select|delete|update|count|master|truncate|declare|\*|%|\')(.*)$ ) { return 403; }
        if ($http_user_agent ~ ApacheBench|WebBench|Jmeter|JoeDog|Havij|GetRight|TurnitinBot|GrabNet|masscan|mail2000|github|wget|curl) { return 444; }
        if ($http_user_agent ~ "Go-Ahead-Got-It") { return 444; }
        if ($http_user_agent ~ "GetWeb!") { return 444; }
        if ($http_user_agent ~ "Go!Zilla") { return 444; }
        if ($http_user_agent ~ "Download Demon") { return 444; }
        if ($http_user_agent ~ "Indy Library") { return 444; }
        if ($http_user_agent ~ "libwww-perl") { return 444; }
        if ($http_user_agent ~ "Nmap Scripting Engine") { return 444; }
        if ($http_user_agent ~ "Load Impact") { return 444; }
        if ($http_user_agent ~ "~17ce.com") { return 444; }
        if ($http_user_agent ~ "WebBench*") { return 444; }
        if ($http_referer ~* 17ce.com) { return 444; }
        if ($http_user_agent ~* qiyunce) { return 444; }
        if ($http_user_agent ~* YunGuanCe) { return 403; }
        if ($http_referer ~* WebBench*") { return 444; }
        if ($http_user_agent ~ "BLEXBot") { return 403; }
        if ($http_user_agent ~ "MJ12bot") { return 403; }
        if ($http_user_agent ~ "semalt.com") { return 403; }
        if ($http_user_agent ~ "sqlmap") { return 403; }

        #自动防护
	if ($request_uri ~* \.(htm|do)\?(.*)$) {
            set $req $2;
        }
        if ($req ~* "(cost\()|(concat\()") {
            return 503;
        }
        if ($req ~* "union[+|(%20)]") {
            return 503;
        }
        if ($req ~* "and[+|(%20)]") {
            return 503;
        }
        if ($req ~* "select[+|(%20)]") {
            return 503;
        }


        #溢出过滤
        if ($query_string ~ "(<|%3C).*script.*(>|%3E)") { return 403; }
        if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { return 403; }
        if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { return 403; }
        if ($query_string ~ "proc/self/environ") { return 403; }
        if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") { return 403; }
        if ($query_string ~ "base64_(en|de)code\(.*\)") { return 403; }

        #文件注入禁止
        if ($query_string ~ "[a-zA-Z0-9_]=http://") { return 403; }
        if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") { return 403; }
        if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") { return 403; }

        location / {

            lua_need_request_body on;
            access_by_lua_block {
                local body = ngx.var.request_body
                if ngx.var.request_method == "POST" and body ~= nil then
                    local regex0 = "(.*?((sqlwhere)|(c0-param0)).*?){1,}"
                    local m0 = ngx.re.match(body, regex0, "i")
                    local regex1 = "(.*?((insert)|(drop)|(truncate)|(update)|(grant)|(chr)|(webscan)|(dbappsecurity)|(WAITFOR)).*?){1,}"
                    local m1 = ngx.re.match(body, regex1, "i")
                    local regex2 = "(.*?((union)|(insert)|(drop)|(truncate)|(grant)|(chr)|(iframe)|(alert)|(webscan)|(dbappsecurity)|(style)|(WAITFOR)|(confirm)|(innerhtml)|(innertext)|(class)).*?){1,}"
                    local m2 = ngx.re.match(body, regex2, "i")
                    if (m0 and m1) or (not m0 and m2) then
                        ngx.log(ngx.ERR, "error: ", body)
                        ngx.status = 403
                        ngx.say('{"code": 403, "msg": "非法参数","ok": false,"runningTime": "0ms"}')
                    end
                end

                ngx.req.read_body()
                local args, err = ngx.req.get_post_args()
                if args then
                    for k, v in pairs(args) do
                       if k == "j_username" or k == "j_password" then
                           local regex = "(.*?((union)|(insert)|(drop)|(truncate)|(update)|(from)|(grant)|(where)|(select)|(chr)|(mid)|(like)|(iframe)|(script)|(alert)|(webscan)|(dbappsecurity)|(style)|(WAITFOR)|(confirm)|(innerhtml)|(innertext)|(class)).*?){1,}"
                           local m = ngx.re.match(v, regex, "i")
                           if m then
                              ngx.log(ngx.ERR, "error: ", v)
                              ngx.status = 403
                              ngx.say('{"code": 403, "msg": "非法参数","ok": false,"runningTime": "0ms"}')
                           end
                       end
                   end
                end
            }


            proxy_http_version 1.1;
            proxy_set_header Connection "";

            proxy_next_upstream http_502 error timeout invalid_header;
            proxy_pass http://192.168.100.199:8888;
            proxy_set_header Host $http_host;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        #自动防护
	if ($request_uri ~* \.(htm|do)\?(.*)$) {
            set $req $2;
        }
        if ($req ~* "(cost\()|(concat\()") {
            return 503;
        }
        if ($req ~* "union[+|(%20)]") {
            return 503;
        }
        if ($req ~* "and[+|(%20)]") {
            return 503;
        }
        if ($req ~* "select[+|(%20)]") {
            return 503;
        }

1、这里之所以使用$request_uri而未使用$query_string变量,因为通过$request_uri进行rewrite分割更精准。

2、%20代表的是空格,同上文不的是,我这里把上面的空格匹配进行了取消。这样像www.361way.com/aaa.do?select * from test之样的也可以进行匹配。

3、上面的htm是伪静态,实际上同.do一样,也是动态文件。为了便于和静态文件进行区分,这里选择了htm而不是html。

4、注意,最上面的url里面的\? ,这个也分重要。如果没有的话,www.361way.com/aaa.htm select * from test不会被过滤,而www.361way.com/aaa.htm?select * from test会被过滤。如果想将前面的也过滤,只需要把\? 取消即可。

https://blog.csdn.net/remotesupport/article/details/11967851

https://blog.csdn.net/qq_34777982/article/details/125390989

http://www.3qphp.com/linux/centos/2581.html

lua-nginx-module的所有指令以及所有方法

http://www.04007.cn/article/430.html

在使用lua时,也许我们很多时候都只用了它几个基础的方法:比如http://www.04007.cn/article/129.html 这里面的content_by_lua,或者content_by_lua_file方法。在nginx+lua的脚本中,我们常用的ngx.say,以及ngx.log等,但实际ngx.还有很多好用的方法。

lua_nginx_module中可使用的指令列表:

指令名称说明
lua_use_default_type是否使用default_type指令定义的Content-Type默认值
lua_code_cache*_by_lua_file文件是否cache
lua_regex_cache_max_entries 
lua_regex_match_limit 
lua_package_path用Lua写的lua外部库路径(.lua文件)
lua_package_cpath用C写的lua外部库路径(.so文件)
init_by_luamaster进程启动时挂载的lua代码
init_by_lua_file 
init_worker_by_luaworker进程启动时挂载的lua代码,常用来执行一些定时器任务
init_worker_by_lua_file 
set_by_lua设置变量
set_by_lua_file 
content_by_luahandler模块
content_by_lua_file 
rewrite_by_lua 
rewrite_by_lua_file 
access_by_lua 
access_by_lua_file 
header_filter_by_luaheader filter模块
header_filter_by_lua_file 
body_filter_by_luabody filter模块,ngx.arg[1]代表输入的chunk,ngx.arg[2]代表当前chunk是否为last
body_filter_by_lua_file 
log_by_lua 
log_by_lua_file 
lua_need_request_body是否读请求体,跟ngx.req.read_body()函数作用类似
lua_shared_dict创建全局共享的table(多个worker进程共享)
lua_socket_connect_timeoutTCP/unix 域socket对象connect方法的超时时间
lua_socket_send_timeoutTCP/unix 域socket对象send方法的超时时间
lua_socket_send_lowat设置cosocket send buffer的low water值
lua_socket_read_timeoutTCP/unix 域socket对象receive方法的超时时间
lua_socket_buffer_sizecosocket读buffer大小
lua_socket_pool_sizecosocket连接池大小
lua_socket_keepalive_timeoutcosocket长连接超时时间
lua_socket_log_errors是否打开cosocket错误日志
lua_ssl_ciphers 
lua_ssl_crl 
lua_ssl_protocols 
lua_ssl_trusted_certificate 
lua_ssl_verify_depth 
lua_http10_buffering 
rewrite_by_lua_no_postpone 
lua_transform_underscores_in_response_headers 
lua_check_client_abort是否监视client提前关闭请求的事件,如果打开监视,会调用ngx.on_abort()注册的回调
lua_max_pending_timers 
lua_max_running_timers 

在lua程序脚本中可使用的操作方法及可取得的变量和常量列表

操作指令说明
ngx.arg指令参数,如跟在content_by_lua_file后面的参数
ngx.var变量,ngx.var.VARIABLE引用某个变量
ngx.ctx请求的lua上下文
ngx.header响应头,ngx.header.HEADER引用某个头
ngx.status响应码
API说明
ngx.log输出到error.log
print等价于 ngx.log(ngx.NOTICE, ...)
ngx.send_headers发送响应头
ngx.headers_sent响应头是否已发送
ngx.resp.get_headers获取响应头
ngx.timer.at注册定时器事件
ngx.is_subrequest当前请求是否是子请求
ngx.location.capture发布一个子请求
ngx.location.capture_multi发布多个子请求
ngx.exec 
ngx.redirect 
ngx.print输出响应
ngx.say输出响应,自动添加'\n'
ngx.flush刷新响应
ngx.exit结束请求
ngx.eof 
ngx.sleep无阻塞的休眠(使用定时器实现)
ngx.get_phase 
ngx.on_abort注册client断开请求时的回调函数
ndk.set_var.DIRECTIVE 
ngx.req.start_time请求的开始时间
ngx.req.http_version请求的HTTP版本号
ngx.req.raw_header请求头(包括请求行)
ngx.req.get_method请求方法
ngx.req.set_method请求方法重载
ngx.req.set_uri请求URL重写
ngx.req.set_uri_args 
ngx.req.get_uri_args获取请求参数
ngx.req.get_post_args获取请求表单
ngx.req.get_headers获取请求头
ngx.req.set_header 
ngx.req.clear_header 
ngx.req.read_body读取请求体
ngx.req.discard_body扔掉请求体
ngx.req.get_body_data 
ngx.req.get_body_file 
ngx.req.set_body_data 
ngx.req.set_body_file 
ngx.req.init_body 
ngx.req.append_body 
ngx.req.finish_body 
ngx.req.socket 
ngx.escape_uri字符串的url编码
ngx.unescape_uri字符串url解码
ngx.encode_args将table编码为一个参数字符串
ngx.decode_args将参数字符串编码为一个table
ngx.encode_base64字符串的base64编码
ngx.decode_base64字符串的base64解码
ngx.crc32_short字符串的crs32_short哈希
ngx.crc32_long字符串的crs32_long哈希
ngx.hmac_sha1字符串的hmac_sha1哈希
ngx.md5返回16进制MD5
ngx.md5_bin返回2进制MD5
ngx.sha1_bin返回2进制sha1哈希值
ngx.quote_sql_strSQL语句转义
ngx.today返回当前日期
ngx.time返回UNIX时间戳
ngx.now返回当前时间
ngx.update_time刷新时间后再返回
ngx.localtime 
ngx.utctime 
ngx.cookie_time返回的时间可用于cookie值
ngx.http_time返回的时间可用于HTTP头
ngx.parse_http_time解析HTTP头的时间
ngx.re.match 
ngx.re.find 
ngx.re.gmatch 
ngx.re.sub 
ngx.re.gsub 
ngx.shared.DICT 
ngx.shared.DICT.get 
ngx.shared.DICT.get_stale 
ngx.shared.DICT.set 
ngx.shared.DICT.safe_set 
ngx.shared.DICT.add 
ngx.shared.DICT.safe_add 
ngx.shared.DICT.replace 
ngx.shared.DICT.delete 
ngx.shared.DICT.incr 
ngx.shared.DICT.flush_all 
ngx.shared.DICT.flush_expired 
ngx.shared.DICT.get_keys 
ngx.socket.udp 
udpsock:setpeername 
udpsock:send 
udpsock:receive 
udpsock:close 
udpsock:settimeout 
ngx.socket.tcp 
tcpsock:connect 
tcpsock:sslhandshake 
tcpsock:send 
tcpsock:receive 
tcpsock:receiveuntil 
tcpsock:close 
tcpsock:settimeout 
tcpsock:setoption 
tcpsock:setkeepalive 
tcpsock:getreusedtimes 
ngx.socket.connect 
ngx.thread.spawn 
ngx.thread.wait 
ngx.thread.kill 
coroutine.create 
coroutine.resume 
coroutine.yield 
coroutine.wrap 
coroutine.running 
coroutine.status 
ngx.config.debug编译时是否有 --with-debug选项
ngx.config.prefix编译时的 --prefix选项
ngx.config.nginx_version返回nginx版本号
ngx.config.nginx_configure返回编译时 ./configure的命令行选项
ngx.config.ngx_lua_version返回ngx_lua模块版本号
ngx.worker.exiting当前worker进程是否正在关闭(如reload、shutdown期间)
ngx.worker.pid返回当前worker进程的pid
  
常量说明
Core constantsngx.OK (0)
ngx.ERROR (-1)
ngx.AGAIN (-2)
ngx.DONE (-4)
ngx.DECLINED (-5)
ngx.nil
HTTP method constantsngx.HTTP_GET
ngx.HTTP_HEAD
ngx.HTTP_PUT
ngx.HTTP_POST
ngx.HTTP_DELETE
ngx.HTTP_OPTIONS  
ngx.HTTP_MKCOL    
ngx.HTTP_COPY      
ngx.HTTP_MOVE     
ngx.HTTP_PROPFIND 
ngx.HTTP_PROPPATCH 
ngx.HTTP_LOCK 
ngx.HTTP_UNLOCK    
ngx.HTTP_PATCH   
ngx.HTTP_TRACE  
HTTP status constantsngx.HTTP_OK (200)
ngx.HTTP_CREATED (201)
ngx.HTTP_SPECIAL_RESPONSE (300)
ngx.HTTP_MOVED_PERMANENTLY (301)
ngx.HTTP_MOVED_TEMPORARILY (302)
ngx.HTTP_SEE_OTHER (303)
ngx.HTTP_NOT_MODIFIED (304)
ngx.HTTP_BAD_REQUEST (400)
ngx.HTTP_UNAUTHORIZED (401)
ngx.HTTP_FORBIDDEN (403)
ngx.HTTP_NOT_FOUND (404)
ngx.HTTP_NOT_ALLOWED (405)
ngx.HTTP_GONE (410)
ngx.HTTP_INTERNAL_SERVER_ERROR (500)
ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
ngx.HTTP_SERVICE_UNAVAILABLE (503)
ngx.HTTP_GATEWAY_TIMEOUT (504) 
Nginx log level constantsngx.STDERR
ngx.EMERG
ngx.ALERT
ngx.CRIT
ngx.ERR
ngx.WARN
ngx.NOTICE
ngx.INFO
ngx.DEBUG

Lua-Nginx-Module常用指令

https://blog.51cto.com/xikder/2331336

https://blog.51cto.com/xikder/2331368

https://blog.51cto.com/xikder/2331504

本章将会讲解基于LuaJIT的Lua-Nginx-Module,它作为Nginx的第三方开源软件,拥有十分丰富的功能,可以轻松完成高并发的业务需求。

注意:本书使用的Lua-Nginx-Module版本是0.10.13。Nginx API for Lua将被简称为Lua API,而Lua-Nginx-Module则被简称为Ngx_lua。后面章节中涉及到的Lua API大部分是包含参数的,如果参数以?结尾,代表这个参数是可选的,如在指令ngx.req.get_headers (max_headers?, raw?)中,max_headers和raw是可选的。

一、Nginx和OpenResty

首先,来认识一下OpenResty,它是一个基于Nginx和Lua开发的高性能的Web平台,包含大量成熟的第三方库,可快速搭建出高性能的Web服务器,支持常用的反向代理、网关系统、Web应用等。

如果在Nginx上使用Ngx_lua,需要先进行编译;而OpenResty已经包含此模块,不需要再进行编译了。读者可以自由选择使用Nginx或OpenResty来搭建服务,如果无法抉择,可参考如下场景。

使用Nginx编译Ngx_Lua的场景

HTTP代理服务器:复杂度较小,只需部分组件即可,且代理服务器一般由运维人员进行维护。使用Nginx的稳定版进行编译,在性能方面会更有保障,而OpenResty是Nginx的主线版,可能会不定期更新。

OpenResty的使用场景

API服务:业务需求多,需要大量组件。
网关系统:需要大量组件和指令来实现动态组件功能。
Web应用服务器:业务服务、页面服务等,如详情页业务的开发。
使用Nginx编写的Lua代码都可以直接迁移到OpenResty上;反之却不一定可行,毕竟OpenResty的组件更多。

二、安装Ngx_lua

请先安装LuaJIT 2.1.0-beta3(详见第6.2节)并需要编译ngx_devel_kit模块。 下面是在Nginx上的安装方式(OpenResty自带此模块,不必安装编译):

1
2
3
4
5
6
7
8
9
10
11
# wget 'http://nginx.org/download/nginx-1.12.2.tar.gz'
# git clone https://github.com/simplresty/ngx_devel_kit.git
# git clone https://github.com/openresty/lua-nginx-module.git
# tar -xzvf nginx-1.12.2.tar.gz
# cd nginx-1.12.2/
# ./configure --prefix=/usr/local/nginx_1.12.2 \
     --add-module=../ngx_devel_kit \
     --add-module=../lua-nginx-module
     --with-ld-opt="-Wl,-rpath,$LUAJIT_LIB"

# make && make install

并不是每个Nginx版本都支持最新的Ngx_lua,目前已知支持最新Ngx_lua的Nginx版本如下:

1
2
3
4
5
6
7
8
1.13.x (last tested: 1.13.6)
1.12.x
1.11.x (last tested: 1.11.2)
1.10.x
1.9.x (last tested: 1.9.15)
1.8.x
1.7.x (last tested: 1.7.10)
1.6.x

如需获取最新版本的支持动态,请参考https://github.com/openresty/lua-nginx-module# nginx-compatibility。

三、牢记context标识

Ngx_lua API指令和Nginx的指令一样,都存在配置环境的约束问题,因此在使用过程中要确保指令的环境符合预期,例如:

1
2
3
4
ngx.var.VARIABLE
语法:ngx.var.VAR_NAME
context(配置环境):set_by_lua*,rewrite_by_lua*,access_by_lua*,content_by_lua*,header_ filter_by_lua*,body_filter_by_lua*,log_by_lua*
context即配置环境,第一次接触Ngx_lua的读者看到这样的配置环境可能会觉得难以理解,因为这还涉及到Ngx_Lua的执行阶段(后面会有介绍)。

四、Hello world

首先,还是来一条经典语句“Hello, world”,在Nginx配置中加入一个server:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
    listen       80;
    server_name  testnginx.com;
    charset koi8-r;
    location = /test {
     #设置文件使用的默认MIME-type,将会增加一个Content-Type:text/plain的响应头
     default_type 'text/plain';    
     -- content_by_lua_block执行阶段
     content_by_lua_block {    
         ngx.say('Hello,world!')
     }
    }
}

访问这个server,输出如下:

1
2
#  curl -I http://testnginx.com/test
Hello,world!    

ngx.say将数据作为响应体输出,返回给客户端,并在末尾加上一个回车符。

代码中用到了content_by_lua_block这个指令块,它的主要作用是在HTTP的内容处理阶段生成数据,详见第8.6节。