Skip to content

feat: add expires timestamp for CSRF plugin#6201

Merged
spacewander merged 12 commits into
apache:masterfrom
Baoyuantop:feat-csrf-expires
Mar 13, 2022
Merged

feat: add expires timestamp for CSRF plugin#6201
spacewander merged 12 commits into
apache:masterfrom
Baoyuantop:feat-csrf-expires

Conversation

@Baoyuantop

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

resolve #6141

Pre-submission checklist:

  • Did you explain what problem does this PR solve? Or what new features have been added?
  • Have you added corresponding test cases?
  • Have you modified the corresponding document?
  • Is this PR backward compatible? If it is not backward compatible, please discuss on the mailing list first

tzssangglass
tzssangglass previously approved these changes Jan 26, 2022
Comment thread t/plugin/csrf.t

=== TEST 10: expired csrf token
--- config
location /t {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the test case doesn't access /t?

@bisakhmondal bisakhmondal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, nice to see this PR.

Comment thread apisix/plugins/csrf.lua Outdated
Comment on lines +78 to +79
local expires_timestamp = ngx_time() + conf.expires
local sign = gen_sign(random, expires_timestamp, conf.key)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say sign with the current timestamp. and at line 116 perform a diff (ngx_time()-expires) and test if it is greater than conf.expires. In this way, expiry is localized to apisix as it supports the current need of the user. Any mistake in setting up conf expiry (maybe a big value) value and the tokens generated with that value can't be used to exploit the infra because generated tokens can be revoked by reconfiguring the expires field.

Also, how about ignoring the check when conf.expires = 0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your guidance.

@bisakhmondal bisakhmondal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for addressing the changes.

Also, how about ignoring the check when conf.expires = 0

What do you think?

@Baoyuantop

Copy link
Copy Markdown
Contributor Author

LGTM. Thanks for addressing the changes.

Also, how about ignoring the check when conf.expires = 0

What do you think?

Agree

Comment thread apisix/plugins/csrf.lua Outdated
Comment on lines +138 to +140
if conf.expires == 0 then
return
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, sorry I confused you. I didn't mean to ignore csrf token validation. I meant we can ignore token has expired check.

Comment thread apisix/plugins/csrf.lua Outdated
Comment on lines +117 to +120
if time_now - expires > conf.expires then
core.log.error("token has expired")
return false
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if time_now - expires > conf.expires then
core.log.error("token has expired")
return false
end
if conf.expires > 0 and time_now - expires > conf.expires then
core.log.error("token has expired")
return false
end

Just that's it.

Comment thread docs/en/latest/plugins/csrf.md Outdated
| 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 all checks**

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**Note: When expires is set to 0 the plugin will ignore all checks**
**Note: When expires is set to 0 the plugin will ignore checking if the token is expired or not.**

Comment thread t/plugin/csrf.t Outdated



=== TEST 12: set expires 0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update it accordingly. Split it into 2 cases

  • expires = 1 sec, sleep = 2 sec after drawing a token then check token has expired
  • expires = 0, sleep = 1, no expiration

@Baoyuantop

Copy link
Copy Markdown
Contributor Author

I have a problem when I change the test: I need to carry the cookie returned from the previous response. Is there any way to do it? The cookie is now encoded in the test code.

@spacewander

Copy link
Copy Markdown
Member

You can refer to:

One request after another:

https://github.com/apache/apisix/blob/master/docs/en/latest/internal/testing-framework.md

tzssangglass
tzssangglass previously approved these changes Mar 10, 2022

@bisakhmondal bisakhmondal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. Thanks, @Baoyuantop for addressing the changes. Some minor nitpicks.

Comment thread t/plugin/csrf.t
if res.status >= 300 then
ngx.status = res.status
end
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread t/plugin/csrf.t Outdated
Comment on lines +213 to +244
=== TEST 12: set expires 1
--- 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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant? /route/1 already has the same config.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, modified

Comment thread t/plugin/csrf.t
Comment on lines +325 to +328
end
ngx.say(res.body)
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
end
ngx.say(res.body)
}
}
end
ngx.status = res.status
ngx.print(res.body)
}
}
--- response_body
hello world

I think you missed checking the response-body. Add this snippet. Thanks

@bisakhmondal bisakhmondal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks, @Baoyuantop

@spacewander
spacewander merged commit cd3e7cd into apache:master Mar 13, 2022
@Baoyuantop
Baoyuantop deleted the feat-csrf-expires branch March 13, 2022 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

improve: use the expiration timestamp in csrf plugin

5 participants