You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apisix.apache.org by Zexuan Luo <sp...@apache.org> on 2021/12/01 06:01:19 UTC

Re: [DISCUSS] Design a CSRF plugin for APISIX

LGTM, only a few questions:

> Random is a random number like ngx.time().

ngx.time isn't a random number.

> core.response.set_header("Set-Cookie",
{"csrf_token="..csrf_token..";path=/"})

We need to use add_header to prevent overriding existing Cookie. And
maybe we use a more specialized field name, like apisix_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)

Which request header?

Baoyuan <ba...@gmail.com> 于2021年11月30日周二 下午9:22写道:
>
> 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 <sp...@apache.org> 于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 <ba...@gmail.com> 于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 <sp...@apache.org> 于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 <ba...@gmail.com> 于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<ba...@gmail.com>
> > > >
> >

Re: [DISCUSS] Design a CSRF plugin for APISIX

Posted by Baoyuan <ba...@gmail.com>.
> ngx.time isn't a random number.
Yes, I'm going to set up the random numbers using math.random()

> Which request header?
A custom request header with a name similar to X-CSRF-Token, or as
specified by the user's configuration

Zexuan Luo <sp...@apache.org> 于2021年12月1日周三 下午2:01写道:

> LGTM, only a few questions:
>
> > Random is a random number like ngx.time().
>
> ngx.time isn't a random number.
>
> > core.response.set_header("Set-Cookie",
> {"csrf_token="..csrf_token..";path=/"})
>
> We need to use add_header to prevent overriding existing Cookie. And
> maybe we use a more specialized field name, like apisix_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)
>
> Which request header?
>
> Baoyuan <ba...@gmail.com> 于2021年11月30日周二 下午9:22写道:
> >
> > 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 <sp...@apache.org> 于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 <ba...@gmail.com> 于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 <sp...@apache.org> 于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 <ba...@gmail.com> 于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<ba...@gmail.com>
> > > > >
> > >
>