【问题标题】:How do I secure a REST API from CSRF when both frontend and API are on the same Go server?当前端和 API 在同一个 Go 服务器上时,如何从 CSRF 保护 REST API?
【发布时间】:2019-03-24 04:10:13
【问题描述】:

我正在开发一个用 Go 创建的网站。

可以通过 Web(通过 golang 模板生成的服务器端页面)和 REST API(对于想要集成自己的软件的外部用户)来访问它。 Go 服务器处理这两种类型的请求,当调用发送到子路径“my-url-root/api”时,子路由器处理 API。

  • 网页使用安全 cookie
  • API 是无状态的:没有 cookie(每个 API 方法必须在 标头是通过专用登录方法获得的身份验证令牌)

我成功地应用了 gorilla/csrf 来保护网页免受 csrf 攻击,但是这种修改(在我上线之前是必不可少的)现在导致 API 出现问题。

我的问题 实施 CSRF 后,发送到 api URL 的所有 GET 请求都按预期工作,但发送的任何其他请求(例如,通过我的 REST api 添加内容的方法的 POST)都会生成一个 html 响应,该响应通常声明“禁止 - 无效的 csrf令牌”。

有没有我想念的直接方法?我搜索了答案,但没有一个适用于 api 由同一台服务器提供服务并且最重要的是它是无状态的情况。 我是否应该看看我是否可以“禁用”子路由器的 gorilla csrf 保护(尽管我什至不知道这是否可能以及这是否安全......)?

感谢您的帮助。

【问题讨论】:

  • 如果你的api实际上是无状态的,我认为它不需要csrf保护..没有cookie ===没有csrf。你可以有2个路由器,一个在/(这里使用csrf中间件),另一个在/api(没有crsf中间件)
  • @adelowo 谢谢!一旦你建议它是可能的,我就尝试了。我创建了一个 SubMux 并用它来处理“/”和“/*”路径(通过使用 gorilla csrf 中间件),然后我创建了另一个 SubMux 来处理没有 csrf 的“/api”和“/api/*”路径。然后我使用浏览器和soapui调用进行了许多测试以检查所有组合并且它有效!
  • 我应该用我的代码示例更新我的问题以帮助社区吗?特别是我对它的工作感到惊讶,因为我认为通过将 CSRF 中间件应用于根“/*”,那么它甚至可以应用于所有下行路径......实际上所有网页,如“/users”,“/ orgs" 使 csrf 处于活动状态(它们都通过分配给我为 URL "/*" 创建的 SubMux 的 SubMuxes 处理)。我想它可以工作,因为我为 URL“/api/*”创建了 SubMux,将其分配给“第一个 mux”,而不是我为根“/*”创建的 SubMux?我正在使用 goji...
  • @Romano 添加解决方案作为答案。
  • 你的路由定义的顺序是什么?

标签: rest go csrf-protection gorilla


【解决方案1】:

好的,所以我尝试应用上面的建议,并想出了解决问题的方法。

我通过检查 web 和 api 调用对我的 url 和子 url 进行测试,无论是否有 csrf 保护。

只是对我之前评论的澄清。更准确地说,我创建 Submux 的顺序无关紧要,但是当我写下处理每条路径的行时,我当然遵循了正确的顺序。

所以,顺序很重要。

这就是我所做的(只是一些代码)。

我使用 goji 作为路由器,使用 gorilla/csrf 进行 csrf 保护。

注意:我没有包含我的所有代码,而只是描述了我所做的最重要的部分。

1) 我使用创建了一个多路复用器

mux := goji.NewMux()

2) 因为我的 API 在 url "/api" 和相关的子 url 下提供,所以我为 api 创建了一个 Submux

apiMux := goji.SubMux()

3)我将匹配路径“/api”和“/api*”的页面分配给这个subMux

请注意,我没有包含任何 csrf 保护

mux.Handle(pat.New("/api/*"), apiMux)

mux.Handle(pat.New("/api"), apiMux)

4) 我为我网站的网页创建了一个 Submux

webMux := goji.SubMux()

5)我将匹配路径“/”和“/*”的页面分配给这个subMux

请注意,在我的代码中,我为 csrf 保护链接了中间件

mux.Handle(pat.New("/"), csrf.Protect(csrfKey, csrf.Secure(true))(webMux))
mux.Handle(pat.New("/*"), csrf.Protect(csrfKey, csrf.Secure(true))(webMux))

6) 为了我的利益,我创建了其他 SubMux 来处理其他路径,例如“/users”、“/users/1”、“/users/addform”。 这一步很重要:我将此“userMux”分配给 webMux,而不是分配给在第 1 步创建的主多路复用器。

这样就继承了csrf保护。示例:

usersMux := goji.SubMux()

webMux.Handle(pat.New("/users/*"), usersMux)

webMux.Handle(pat.New("/users"), usersMux)

简而言之,这就是我的问题的解决方案:

I) 我将此“apiMux”分配给在步骤 1 中创建的主多路复用器。

我没有将它分配给任何其他多路复用器。我没有将它分配给处理根 url“/”和“/*”的 webMux

II) 顺序很重要,所以我实现了 API url 的代码,然后实现了 web url 的代码

我希望它有所帮助。最重要的是,我希望解释清楚......(如果不只是让我知道的话)。 感谢您为我指明正确的方向

【讨论】:

    猜你喜欢
    • 2021-10-25
    • 2018-02-06
    • 2021-03-08
    • 2016-09-05
    • 2017-01-21
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    相关资源
    最近更新 更多