You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2023/03/02 09:03:46 UTC

[apisix] 01/02: fix(proxy-rewrite): escape args part if it's not from user conf (#8888)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch release/2.15
in repository https://gitbox.apache.org/repos/asf/apisix.git

commit ca0c7d9da8e4b0241720a5fc46baa5baad826f74
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Fri Feb 24 09:31:08 2023 +0800

    fix(proxy-rewrite): escape args part if it's not from user conf (#8888)
---
 apisix/core/utils.lua            |   8 +-
 apisix/plugins/proxy-rewrite.lua |  27 +++++--
 t/plugin/proxy-rewrite3.t        | 168 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 193 insertions(+), 10 deletions(-)

diff --git a/apisix/core/utils.lua b/apisix/core/utils.lua
index f72996b78..01c8b34c8 100644
--- a/apisix/core/utils.lua
+++ b/apisix/core/utils.lua
@@ -293,6 +293,7 @@ do
     local _ctx
     local n_resolved
     local pat = [[(?<!\\)\$\{?(\w+)\}?]]
+    local _escaper
 
     local function resolve(m)
         local v = _ctx[m[1]]
@@ -300,10 +301,13 @@ do
             return ""
         end
         n_resolved = n_resolved + 1
+        if _escaper then
+            return _escaper(tostring(v))
+        end
         return tostring(v)
     end
 
-    function resolve_var(tpl, ctx)
+    function resolve_var(tpl, ctx, escaper)
         n_resolved = 0
         if not tpl then
             return tpl, nil, n_resolved
@@ -316,8 +320,10 @@ do
 
         -- avoid creating temporary function
         _ctx = ctx
+        _escaper = escaper
         local res, _, err = re_gsub(tpl, pat, resolve, "jo")
         _ctx = nil
+        _escaper = nil
         if not res then
             return nil, err
         end
diff --git a/apisix/plugins/proxy-rewrite.lua b/apisix/plugins/proxy-rewrite.lua
index f53918003..9ef3b5f9f 100644
--- a/apisix/plugins/proxy-rewrite.lua
+++ b/apisix/plugins/proxy-rewrite.lua
@@ -165,13 +165,24 @@ function _M.rewrite(conf, ctx)
         ctx.upstream_scheme = conf["scheme"]
     end
 
+
+    local function escape_separator(s)
+        return re_sub(s, [[\?]], "%3F", "jo")
+    end
+
     local upstream_uri = ctx.var.uri
+    local separator_escaped = false
     if conf.use_real_request_uri_unsafe then
         upstream_uri = ctx.var.real_request_uri
     elseif conf.uri ~= nil then
-        upstream_uri = core.utils.resolve_var(conf.uri, ctx.var)
+        separator_escaped = true
+        upstream_uri = core.utils.resolve_var(conf.uri, ctx.var, escape_separator)
     elseif conf.regex_uri ~= nil then
-        local uri, _, err = re_sub(ctx.var.uri, conf.regex_uri[1],
+        if not str_find(upstream_uri, "?") then
+            separator_escaped = true
+        end
+
+        local uri, _, err = re_sub(upstream_uri, conf.regex_uri[1],
                                    conf.regex_uri[2], "jo")
         if uri then
             upstream_uri = uri
@@ -185,11 +196,17 @@ function _M.rewrite(conf, ctx)
     end
 
     if not conf.use_real_request_uri_unsafe then
-        local index = str_find(upstream_uri, "?")
+        local index
+        if separator_escaped then
+            index = str_find(upstream_uri, "?")
+        end
+
         if index then
-            upstream_uri = core.utils.uri_safe_encode(sub_str(upstream_uri, 1, index-1)) ..
-                           sub_str(upstream_uri, index)
+            upstream_uri = core.utils.uri_safe_encode(sub_str(upstream_uri, 1, index - 1)) ..
+                sub_str(upstream_uri, index)
         else
+            -- The '?' may come from client request '%3f' when we use ngx.var.uri directly or
+            -- via regex_uri
             upstream_uri = core.utils.uri_safe_encode(upstream_uri)
         end
 
diff --git a/t/plugin/proxy-rewrite3.t b/t/plugin/proxy-rewrite3.t
index 7501abd1d..0bedf09d4 100644
--- a/t/plugin/proxy-rewrite3.t
+++ b/t/plugin/proxy-rewrite3.t
@@ -327,8 +327,6 @@ ngx.var.request_uri: /print_uri_detailed
 GET /t
 --- response_body
 passed
---- no_error_log
-[error]
 
 
 
@@ -339,5 +337,167 @@ GET /echo HTTP/1.1
 X-Forwarded-Host: apisix.ai
 --- response_headers
 X-Forwarded-Host: test.com
---- no_error_log
-[error]
+
+
+
+=== TEST 14: set route
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                      "plugins": {
+                          "proxy-rewrite": {
+                              "host": "test.xxxx.com"
+                          }
+                      },
+                      "upstream": {
+                          "nodes": {
+                              "127.0.0.1:8125": 1
+                          },
+                          "type": "roundrobin"
+                      },
+                      "uri": "/hello*"
+                 }]]
+                 )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 15: hit with CRLF
+--- request
+GET /hello%3f0z=700%26a=c%20HTTP/1.1%0D%0AHost:google.com%0d%0a%0d%0a
+--- http_config
+    server {
+        listen 8125;
+        location / {
+            content_by_lua_block {
+                ngx.say(ngx.var.host)
+                ngx.say(ngx.var.request_uri)
+            }
+        }
+    }
+--- response_body
+test.xxxx.com
+/hello%3F0z=700&a=c%20HTTP/1.1%0D%0AHost:google.com%0D%0A%0D%0A
+
+
+
+=== TEST 16: set route with uri
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                      "plugins": {
+                          "proxy-rewrite": {
+                              "uri": "/$uri/remain",
+                              "host": "test.xxxx.com"
+                          }
+                      },
+                      "upstream": {
+                          "nodes": {
+                              "127.0.0.1:8125": 1
+                          },
+                          "type": "roundrobin"
+                      },
+                      "uri": "/hello*"
+                 }]]
+                 )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 17: hit with CRLF
+--- request
+GET /hello%3f0z=700%26a=c%20HTTP/1.1%0D%0AHost:google.com%0d%0a%0d%0a
+--- http_config
+    server {
+        listen 8125;
+        location / {
+            content_by_lua_block {
+                ngx.say(ngx.var.host)
+                ngx.say(ngx.var.request_uri)
+            }
+        }
+    }
+--- response_body
+test.xxxx.com
+//hello%253F0z=700&a=c%20HTTP/1.1%0D%0AHost:google.com%0D%0A%0D%0A/remain
+
+
+
+=== TEST 18: regex_uri with args
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                      "plugins": {
+                          "proxy-rewrite": {
+                              "regex_uri": ["^/test/(.*)/(.*)/(.*)", "/$1_$2_$3?a=c"]
+                          }
+                      },
+                      "upstream": {
+                          "nodes": {
+                              "127.0.0.1:8125": 1
+                          },
+                          "type": "roundrobin"
+                      },
+                      "uri": "/test/*"
+                 }]]
+                 )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 19: hit
+--- request
+GET /test/plugin/proxy/rewrite HTTP/1.1
+--- http_config
+    server {
+        listen 8125;
+        location / {
+            content_by_lua_block {
+                ngx.say(ngx.var.request_uri)
+            }
+        }
+    }
+--- response_body
+/plugin_proxy_rewrite?a=c