×

为什么说在nginx location里使用 if 指令是邪恶的?

Falcon 2021-05-12 views:
自动摘要

正在生成中……

为什么if是邪恶的?

if 指令在location里使用经常会出现不符合期望的情形,有时甚至会出现段错误(segfaults),这是因为if指令是重写模块的一部分,该模块命令式地计算指令。另一方面,NGINX配置是声明性的语言。但某些情况,由于用户的需要,会尝试在if中使用一些非重写指令

这就导致了现在的情况。它总体上是有效的,不过有一些情况可能并不如你所愿,比如:

# Here is collection of unexpectedly buggy configurations to show that
# if inside location is evil.

# only second header will be present in response
# not really bug, just how it works

location /only-one-if {
    set $true 1;

    if ($true) {
        add_header X-First 1;
    }

    if ($true) {
        add_header X-Second 2;
    }

    return 204;
}

# request will be sent to backend without uri changed
# to '/' due to if

location /proxy-pass-uri {
    proxy_pass http://127.0.0.1:8080/;

    set $true 1;

    if ($true) {
        # nothing
    }
}

# try_files wont work due to if

location /if-try-files {
     try_files  /file  @fallback;

     set $true 1;

     if ($true) {
         # nothing
     }
}

# nginx will SIGSEGV

location /crash {

    set $true 1;

    if ($true) {
        # fastcgi_pass here
        fastcgi_pass  127.0.0.1:9000;
    }

    if ($true) {
        # no handler here
    }
}

# alias with captures isn't correcly inherited into implicit nested
# location created by if

location ~* ^/if-and-alias/(?<file>.*) {
    alias /tmp/$file;

    set $true 1;

    if ($true) {
        # nothing
    }
}

 

只有两种情况是100%安全的。

if ($request_method = POST ) { return 405; } 

if ($args ~ post=140){ rewrite ^ http://example.com/ permanent; }

如何避免?

除了使用 try_files  和上面提到的 return ...;rewrite ... last; 外,还可以把if移到server块,因为只有其他重写模块指令被允许在里面,这是安全的。

参考:https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

本文收录于