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 2022/03/13 11:34:05 UTC
[apisix] branch master updated: feat: add expires timestamp for CSRF plugin (#6201)
This is an automated email from the ASF dual-hosted git repository.
spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new cd3e7cd feat: add expires timestamp for CSRF plugin (#6201)
cd3e7cd is described below
commit cd3e7cdb490071d5231490b623e6b35a5fc985ac
Author: Baoyuan <ba...@gmail.com>
AuthorDate: Sun Mar 13 19:34:00 2022 +0800
feat: add expires timestamp for CSRF plugin (#6201)
---
apisix/plugins/csrf.lua | 10 ++-
docs/en/latest/plugins/csrf.md | 2 +
docs/zh/latest/plugins/csrf.md | 2 +
t/plugin/csrf.t | 179 +++++++++++++++++++++++++++++++++++++++--
4 files changed, 186 insertions(+), 7 deletions(-)
diff --git a/apisix/plugins/csrf.lua b/apisix/plugins/csrf.lua
index 40ea519..233fe1d 100644
--- a/apisix/plugins/csrf.lua
+++ b/apisix/plugins/csrf.lua
@@ -75,11 +75,12 @@ end
local function gen_csrf_token(conf)
local random = math.random()
- local sign = gen_sign(random, conf.expires, conf.key)
+ local timestamp = ngx_time()
+ local sign = gen_sign(random, timestamp, conf.key)
local token = {
random = random,
- expires = conf.expires,
+ expires = timestamp,
sign = sign,
}
@@ -112,6 +113,11 @@ local function check_csrf_token(conf, ctx, token)
core.log.error("no expires in token")
return false
end
+ local time_now = ngx_time()
+ if conf.expires > 0 and time_now - expires > conf.expires then
+ core.log.error("token has expired")
+ return false
+ end
local sign = gen_sign(random, expires, conf.key)
if token_table["sign"] ~= sign then
diff --git a/docs/en/latest/plugins/csrf.md b/docs/en/latest/plugins/csrf.md
index 8f2efe3..5300d6e 100644
--- a/docs/en/latest/plugins/csrf.md
+++ b/docs/en/latest/plugins/csrf.md
@@ -35,6 +35,8 @@ In the following we define `GET`, `HEAD` and `OPTIONS` as the `safe-methods` and
| expires | number | optional | `7200` | | Expiration time(s) of csrf cookie. |
| key | string | required | | | The secret key used to encrypt the cookie. |
+**Note: When expires is set to 0 the plugin will ignore checking if the token is expired or not.**
+
## How To Enable
1. Create the route and enable the plugin.
diff --git a/docs/zh/latest/plugins/csrf.md b/docs/zh/latest/plugins/csrf.md
index a007cbf..9fdea38 100644
--- a/docs/zh/latest/plugins/csrf.md
+++ b/docs/zh/latest/plugins/csrf.md
@@ -35,6 +35,8 @@ title: csrf
| expires | number | optional | `7200` | | CSRF Cookie 的过期时间(秒) |
| key | string | required | | | 加密 token 的秘钥 |
+**注意:当 expires 设置为 0 时插件将忽略检查 Token 是否过期**
+
## 如何启用
1. 创建一条路由并启用该插件。
diff --git a/t/plugin/csrf.t b/t/plugin/csrf.t
index 2f293ac..2bbd700 100644
--- a/t/plugin/csrf.t
+++ b/t/plugin/csrf.t
@@ -73,7 +73,8 @@ done
},
"plugins": {
"csrf": {
- "key": "userkey"
+ "key": "userkey",
+ "expires": 1000000000
}
}
}]]
@@ -145,8 +146,8 @@ Cookie: apisix-csrf-token=testcookie
--- request
POST /hello
--- more_headers
-apisix-csrf-token: eyJleHBpcmVzIjo3MjAwLCJyYW5kb20iOjAuMjE2ODAxOTYyNTEwNDEsInNpZ24iOiJqZnhDckk1TVwvMHI3VjdyWWRBSXNCeEg3emljY3VnV0dySGtYQkZ0QT0ifQ==
-Cookie: apisix-csrf-token=eyJleHBpcmVzIjo3MjAwLCJyYW5kb20iOjAuMjE2ODAxOTYyNTEwNDEsInNpZ24iOiJqZnhDckk1TVwvMHI3VjdyWWRBSXNCeEg3emljY3VnV0dySGtYQkZ0QT0ifQ==
+apisix-csrf-token: eyJyYW5kb20iOjAuMTYwOTgzMDYwMTg0NDksInNpZ24iOiI2YTEyYmViYTI4MzAyNDg4MDRmNGU0N2VkZDY5MWFmNjg5N2IyNzQ4YTY1YWMwMDJiMGFjMzFlN2NlMDdlZTViIiwiZXhwaXJlcyI6MTc0MzExOTkxMX0=
+Cookie: apisix-csrf-token=eyJyYW5kb20iOjAuMTYwOTgzMDYwMTg0NDksInNpZ24iOiI2YTEyYmViYTI4MzAyNDg4MDRmNGU0N2VkZDY5MWFmNjg5N2IyNzQ4YTY1YWMwMDJiMGFjMzFlN2NlMDdlZTViIiwiZXhwaXJlcyI6MTc0MzExOTkxMX0=
--- error_code: 401
--- error_log: Invalid signatures
--- response_body
@@ -158,5 +159,173 @@ Cookie: apisix-csrf-token=eyJleHBpcmVzIjo3MjAwLCJyYW5kb20iOjAuMjE2ODAxOTYyNTEwND
--- request
POST /hello
--- more_headers
-apisix-csrf-token: eyJzaWduIjoiZTlhNWVkOTBmZDc2YjRhMTYyMzg1ZDU2Y2ZhZDI1N2MxNmI0MWY1MjFjZWUwODczNzExM2NlYzZkZDQwMWJmNyIsInJhbmRvbSI6MC4zNjcxNDg2NDI2MjE0MywiZXhwaXJlcyI6NzIwMH0=
-Cookie: apisix-csrf-token=eyJzaWduIjoiZTlhNWVkOTBmZDc2YjRhMTYyMzg1ZDU2Y2ZhZDI1N2MxNmI0MWY1MjFjZWUwODczNzExM2NlYzZkZDQwMWJmNyIsInJhbmRvbSI6MC4zNjcxNDg2NDI2MjE0MywiZXhwaXJlcyI6NzIwMH0=
+apisix-csrf-token: eyJyYW5kb20iOjAuNDI5ODYzMTk3MTYxMzksInNpZ24iOiI0ODRlMDY4NTkxMWQ5NmJhMDc5YzQ1ZGI0OTE2NmZkYjQ0ODhjODVkNWQ0NmE1Y2FhM2UwMmFhZDliNjE5OTQ2IiwiZXhwaXJlcyI6MjY0MzExOTYyNH0=
+Cookie: apisix-csrf-token=eyJyYW5kb20iOjAuNDI5ODYzMTk3MTYxMzksInNpZ24iOiI0ODRlMDY4NTkxMWQ5NmJhMDc5YzQ1ZGI0OTE2NmZkYjQ0ODhjODVkNWQ0NmE1Y2FhM2UwMmFhZDliNjE5OTQ2IiwiZXhwaXJlcyI6MjY0MzExOTYyNH0=
+
+
+
+=== TEST 10: change expired
+--- 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,
+ [[{
+ "uri": "/hello",
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ },
+ "plugins": {
+ "csrf": {
+ "key": "userkey",
+ "expires": 1
+ }
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 11: expired csrf token
+--- request
+POST /hello
+--- more_headers
+apisix-csrf-token: eyJyYW5kb20iOjAuMDY3NjAxMDQwMDM5MzI4LCJzaWduIjoiOTE1Yjg2MjBhNTg1N2FjZmIzNjIxOTNhYWVlN2RkYjY5NmM0NWYwZjE5YjY5Zjg3NjM4ZTllNGNjNjYxYjQwNiIsImV4cGlyZXMiOjE2NDMxMjAxOTN9
+Cookie: apisix-csrf-token=eyJyYW5kb20iOjAuMDY3NjAxMDQwMDM5MzI4LCJzaWduIjoiOTE1Yjg2MjBhNTg1N2FjZmIzNjIxOTNhYWVlN2RkYjY5NmM0NWYwZjE5YjY5Zjg3NjM4ZTllNGNjNjYxYjQwNiIsImV4cGlyZXMiOjE2NDMxMjAxOTN9
+--- error_code: 401
+--- error_log: token has expired
+
+
+
+=== TEST 12: token has expired after sleep 2s
+--- config
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port
+ .. "/hello"
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri(uri, {method = "GET"})
+ if not res then
+ ngx.say(err)
+ return
+ end
+ local cookie = res.headers["Set-Cookie"]
+ local token = cookie:match("=([^;]+)")
+
+ ngx.sleep(2)
+
+ local res, err = httpc:request_uri(uri, {
+ method = "POST",
+ headers = {
+ ["apisix-csrf-token"] = token,
+ ["Cookie"] = cookie,
+ }
+ })
+ if not res then
+ ngx.say(err)
+ return
+ end
+
+ if res.status >= 300 then
+ ngx.status = res.status
+ end
+ }
+ }
+--- error_code: 401
+--- error_log: token has expired
+
+
+
+=== TEST 13: set expires 0
+--- 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,
+ [[{
+ "uri": "/hello",
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ },
+ "plugins": {
+ "csrf": {
+ "key": "userkey",
+ "expires": 0
+ }
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 14: token no expired after sleep 1s
+--- config
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port
+ .. "/hello"
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri(uri, {method = "GET"})
+ if not res then
+ ngx.say(err)
+ return
+ end
+
+ ngx.sleep(1)
+
+ local cookie = res.headers["Set-Cookie"]
+ local token = cookie:match("=([^;]+)")
+
+ local res, err = httpc:request_uri(uri, {
+ method = "POST",
+ headers = {
+ ["apisix-csrf-token"] = token,
+ ["Cookie"] = cookie,
+ }
+ })
+ if not res then
+ ngx.say(err)
+ return
+ end
+
+ if res.status >= 300 then
+ ngx.status = res.status
+ end
+ ngx.status = res.status
+ ngx.print(res.body)
+ }
+ }
+--- response_body
+hello world