Based on the previous discussion, I am designing a plugin for APISIX to
protect the API from CSRF attacks. The following are the specific
implementation details and some sample codes.
1. *Configuration*
- key: User-set secret key, used to generate csrf token
- expires: token expiration time
2. *Details*
*2.1 generate token*
Generating a token requires random, expires, and key.
Expires and key need to be obtained from the plugin's configuration.
Random is a random number like ngx.time().
First, random, expires, and the key is subjected to sha256 operations to
obtain a signature, then the token is obtained by performing base64
operations on the signature and random and expires.
```
local sign = {
random = random,
expires = expires,
key = key,
}
sha256:update(core.json.encode(sign))
local digest = sha256:final()
local token = {
random = random,
expires = expires,
digest = digest,
}
local cookie = ngx_encode_base64(core.json.encode(token))
```
*2.2 Send to the client*
In the header_filter, add a Set-Cookie to the response header if it is a
GET request, with the token generated above.
```
core.response.set_header("Set-Cookie",
{"csrf_token="..csrf_token..";path=/"})
```
*2.3 Checking CSRF token*
Check the following in the request with the plugin enabled:
- Whether or not it carries a cookie containing a CSRF token;
- Whether the request header contains a CSRF token; (This relies on the
user reading the token from the cookie and carrying it to the request
header, as we can explain in the plugin's usage documentation)
- Check that the contents of the two tokens are the same;
- Deconstruct the token base64 and check for expiration by expires;
- Recalculate the signature using the random and expires obtained by
untangling the token, plus the key obtained from the configuration, and
compare the two signatures for consistency;
If all checks pass, the request is passed. Otherwise, 401 is returned to
the client to intercept the request.
This is basic security based on the inability to generate a token that
matches the signature without the user's secret key.
About this design and process, any thoughts or suggestions?
Zexuan Luo <[email protected]> 于2021年11月11日周四 下午2:31写道:
> I suggest you read through the definition of Double
> Submit Cookie:
> https://github.com/OWASP/CheatSheetSeries/blob/5a1044e38778b42a19c6adbb4dfef7a0fb071099/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md#double-submit-cookie
> ,
> especially the drawback part.
>
> And we need to share more details about how does the plugin generate
> the random token and how does the client interact with the server. To
> avoid vulnerability in this plugin, we need to review it closer.
>
> Baoyuan <[email protected]> 于2021年11月11日周四 上午11:36写道:
> >
> > Thank you very much, Zexuan Luo. I thought about it like this
> >
> > > how to let the client know & set the token?
> >
> > I think I can use Set-Cookie to pass it to the client, the client reads
> the
> > content of the token from the cookie and sets it in the request header.
> > I found that in the server rendering web page structure, it is usually
> > placed in the web page DOM so that the client can be easily carried, But
> > for the restful API structure, I think this method can be done.
> >
> > > what token does the client set? It can't just echo back the encrypted
> > csrf token
> >
> > At present, I really think about it this way, which is to return the
> > encrypted csrf token, I don't understand the problem too much.
> >
> >
> >
> > Zexuan Luo <[email protected]> 于2021年11月10日周三 上午10:18写道:
> >
> > > I have read through the definition of Double
> > > Submit Cookie:
> > >
> https://github.com/OWASP/CheatSheetSeries/blob/5a1044e38778b42a19c6adbb4dfef7a0fb071099/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md#double-submit-cookie
> > >
> > > > the CSRF plugin sets a cookie to the client in each request,
> > > which contains the encrypted csrf token, and the client sets it on the
> > > request header in subsequent requests
> > >
> > > The OWASP guide has listed some drawbacks of csrf token without
> encryption.
> > > The proposal mentions that the client will set the encrypted csrf
> > > token in subsequent requests, then there will be two questions:
> > > 1. how to let the client know & set the token?
> > > 2. what token does the client set? It can't just echo back the
> > > encrypted csrf token
> > >
> > > Baoyuan <[email protected]> 于2021年11月9日周二 下午9:36写道:
> > > >
> > > > Hi Community, I have an idea to design a CSRF plugin for APISIX, the
> > > > purpose is to avoid the danger of routing attacks from CSRF.
> > > >
> > > > Taking into account the stateless nature of APISIX, I plan to use
> Double
> > > > Submit Cookie to verify CSRF attacks.
> > > >
> > > > Simply put, the CSRF plugin sets a cookie to the client in each
> request,
> > > > which contains the encrypted csrf token, and the client sets it on
> the
> > > > request header in subsequent requests. CSRF plugin compares and
> verifies
> > > > the request header with the cookie to prevent CSRF attacks.
> > > >
> > > > The CSRF plugin has two configuration items: key and expires. The key
> > > > requires the user to provide a secret key, and the plugin will
> generate
> > > an
> > > > encrypted cookie based on HMAC the token with this secret key. The
> > > expires
> > > > refers to the cookie expiration time, this is an option, if the user
> does
> > > > not provide, the plugin will provide an appropriate default value.
> > > >
> > > > The plugin works at the route level. Users can turn on the plugin on
> the
> > > > desired route to avoid CSRF attacks on the route as much as possible.
> > > >
> > > > Any ideas or suggestions for these?
> > > >
> > > >
> > > > Best Regards!
> > > >
> > > > Yuan Bao<[email protected]>
> > >
>