CSRF保护-JWT和CORS白名单组合是否足够? [英] CSRF protection - is a JWT and CORS whitelist combination sufficient?

查看:495
本文介绍了CSRF保护-JWT和CORS白名单组合是否足够?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力解决我的React/Phoenix应用程序中的CSRF漏洞,在我看来,我的应用程序是安全的...但是我不是这些问题的专家,所以我想求助于社区看看我是否忽略了某些事情或天真了.

Phoenix是一个纯API,与React客户端分开运行,因此我要处理CORS-在Phoenix router.ex中设置允许的来源白名单:

pipeline :api do
  plug CORSPlug, [origin: "localhost:3000"]
  plug :accepts, ["json"]
  plug Guardian.Plug.VerifyHeader, realm: "Bearer"
  plug Guardian.Plug.LoadResource
end

,正如您所看到的,我正在使用Guardian(使用JWT进行用户身份验证)来处理授权.

经授权的客户端将JWT存储在localStorage中,Guardian设置为在请求的Authorization标头中查找该值,作为Bearer ...受保护的Phoenix控制器包括:

plug Guardian.Plug.EnsureAuthenticated

我设置了一个测试攻击者,该攻击者在localhost:5000上运行,以尝试模拟CSRF攻击.首先,我尝试了AJAX攻击-我从登录窗口的localStorage复制了有效的JWT值,并将其设置在模拟攻击者的请求标头中.正如预期的那样,此操作失败,因为localhost:5000未列入白名单

The 'Access-Control-Allow-Origin' header contains the invalid value 'null'. Origin 'http://localhost:5000' is therefore not allowed access.

为了进行测试,我将localhost:5000添加到Phoenix白名单中,并且该请求确实确实有效...因此,即使攻击者设法窃取了有效的JWT,白名单也会将其阻止. /p>

然后,我测试了从OWASP文档借来的自动表单提交:

<body onload='document.CSRF.submit()'>
    <form action='http://localhost:4000/api/v1/user' method='POST' name='CSRF'>
        <input type='hidden' name='name' value='Hacked'>
        <input type='hidden' name='password' value='Hacked'>
    </form>
<body>

,但是由于没有Authorization标头也没有有效的JWT,因此被API控制器中设置的Guardian.Plug.EnsureAuthenticated捕获了:

[info] POST /api/v1/user
[debug] Processing with MyApp.UserController.create/2
  Parameters: %{"name" => "Hacked", "password" => "[FILTERED]"}
  Pipelines: [:api]
[info] Sent 401 in 21ms
[debug] MyApp.UserController halted in 
Guardian.Plug.EnsureAuthenticated.call/2

所以我的印象是,由于CORS白名单,即使使用有效的JWT,AJAX攻击也将失败.简单的请求将失败,因为它们不包含Authorization标头.

在使用JWT进行授权时,我已经阅读了很多有关CSRF保护的信息,但是似乎没有两个人可以就什么是安全和不安全达成共识.我是否缺少某些东西,还是CORS白名单和Guardian JWT检查的组合足以保护抵制CSRF?

解决方案

您提到了两种预防CSRF的方法:1)CORS& 2)JWT存储在localStorage中并与用户会话相关联.我想同时解决这两个问题:

1)CORS通过阻止来自非起源源的尝试代表用户发出HTTP请求,确实有助于防止某些类型的CSRF攻击.这样可以防止从外部来源进行GET/POST,这是一件好事.它不会阻止来自内部来源的CSRF攻击. 继续执行#2 ...

2)通过Authentication/Bearer标头传递给localStorage的JWT可以提供帮助,但始终容易受到XSS攻击.预防XSS至关重要.现在可以通过javascript访问JWT,并且可以与任何请求一起传递.为了提供帮助,网站应阻止Javascript访问令牌..推荐的方法是将JWT存储在HTTPOnly cookie中.该cookie是Authentication/Bearer标头的补充.在Phoenix服务器端,API需要执行的第一步授权步骤是确保来自HTTPOnly cookie的JWT与Authentication/Bearer标头相同.只有这样,API才能被成功调用.

I'm working to address CSRF vulnerabilities in my React/Phoenix app, and it seems to me like my app is safe... but I'm not an expert in these matters, and wanted to turn to the community to see if I've overlooked something or am being naïve.

The Phoenix is a pure API, running separately from the React client, so I'm dealing with CORS - the whitelist of allowed origins is set in the Phoenix router.ex:

pipeline :api do
  plug CORSPlug, [origin: "localhost:3000"]
  plug :accepts, ["json"]
  plug Guardian.Plug.VerifyHeader, realm: "Bearer"
  plug Guardian.Plug.LoadResource
end

and, as you can see, I'm using Guardian (which uses JWT for user authentication) for handling authorization.

Authorized clients store the JWT in localStorage, and Guardian is set to look for that value in the Authorization header of requests as a Bearer... protected Phoenix controllers include:

plug Guardian.Plug.EnsureAuthenticated

I set up a test attacker, running on localhost:5000 to try to mock a CSRF attack. First, I tried an AJAX attack - I copied a valid JWT value from the localStorage of a logged-in window and set it in the request header of my mock attacker. As expected, this fails because localhost:5000 is not whitelisted

The 'Access-Control-Allow-Origin' header contains the invalid value 'null'. Origin 'http://localhost:5000' is therefore not allowed access.

To test, I added localhost:5000 to the Phoenix whitelist and the request did indeed work... so it seems that, even if an attacker managed to steal a valid JWT, they'd be stopped by the whitelist.

I then tested an automated form submission, borrowed from the OWASP docs:

<body onload='document.CSRF.submit()'>
    <form action='http://localhost:4000/api/v1/user' method='POST' name='CSRF'>
        <input type='hidden' name='name' value='Hacked'>
        <input type='hidden' name='password' value='Hacked'>
    </form>
<body>

but this gets caught by Guardian.Plug.EnsureAuthenticated, set in the API's controllers, since there is no Authorization header nor valid JWT present:

[info] POST /api/v1/user
[debug] Processing with MyApp.UserController.create/2
  Parameters: %{"name" => "Hacked", "password" => "[FILTERED]"}
  Pipelines: [:api]
[info] Sent 401 in 21ms
[debug] MyApp.UserController halted in 
Guardian.Plug.EnsureAuthenticated.call/2

So my impression is that AJAX attacks will fail, even with a valid JWT, because of the CORS whitelist... simple requests will fail because they don't include the Authorization header.

I've been reading a lot about CSRF protection when using JWTs for authorization, but it seems like no two people can agree on what is and isn't safe. Am I missing something, or is the combination of the CORS whitelist and Guardian JWT check sufficient to protect agains CSRF?

解决方案

You mention 2 methods for CSRF prevention: 1) CORS & 2) JWT stored in localStorage and associated to the user's session. I would like to address both:

1) CORS does help prevent certain types of CSRF attacks by preventing attempts from non-origin sources from making HTTP requests on the user's behalf. This prevents GETs/POSTs from external sources, good job. It will not prevent CSRF attacks from internal sources. So on to #2...

2) JWT stored in localStorage passed thru Authentication/Bearer header can help but is always still susceptible to XSS attacks. XSS prevention is critical. Now the JWT is accessible via javascript and can be passed with any request. To help, the website should prevent javascript access to the token. The recommended approach is to store the JWT in an HTTPOnly cookie. This cookie is in addition to the Authentication/Bearer header. On the Phoenix server side, the first authorization step the API needs to do is ensure that the JWT from the HTTPOnly cookie is the same as the Authentication/Bearer header. Only then can the API be successfully invoked.

这篇关于CSRF保护-JWT和CORS白名单组合是否足够?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆