Nginx的merge_slashes解析
Nginx有一个配置项是merge_slashes,官方的说明如下:
Syntax: merge_slashes on off;
Default: merge_slashes on;
Context: http, server
Enables or disables compression of two or more adjacent slashes in a URI into a single slash.
顾名思义,就是会在处理URI时将相邻的单斜杠合并。这个配置项在Nginx中对应的源码是在https://github.com/nginx/nginx/blob/master/src/http/ngx_http_parse.c#L1248,该函数的声明是:
ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
第一个参数是URI的请求结构,第二个int类型参数merge_slashes就是配置项的开(on)或关(off)。
函数中,首先有一个枚举类型的变量state用于函数执行中标识每个字符的状态,或者是字符的分类,初始情况下是sw_usual正常状态。
1 | enum { |
字符型指针*u在函数执行过程中用于记录处理的中间URI字符串,字符型指针*p是URI的字符串,字符ch用于记录当前在处理中的URI的字符。
接着是一个大的while循环,用于逐个处理URI中的字符:
1 | ch = *p++; |
函数根据每个处理的字符类型标识当前字符的状态或类型,该状态决定在之后的条件判断语句中该如何处理后续字符。通过以上函数的逻辑可知,如果merge_slashes为1,相邻出现的多个单斜杠会在sw_slash状态的条件处理中被忽略,*u不记录单斜杠,如果为0,则会记录单斜杠字符。
因此,多个斜杠相邻的URI会被处理为单个斜杠,如果需要在URI中传输BASE64字符,则需要关闭merge_slashes,避免其中的斜杠被处理。
另外,如果URI中存在路径穿越的利用,比如“/../../../”,会条件处理到sw_dot_dot中,并返回NGX_HTTP_PARSE_INVALID_REQUEST,即无效的请求。所以Nginx默认情况下可以防范路径穿越攻击,除非将merge_slashes参数设置为关闭。