Golang与React的CSRF问题

huangapple go评论85阅读模式
英文:

Golang CSRF issues with React

问题

我正在创建一个使用Go编写的后端的React应用程序。我已经使用Gorilla库设置了CSRF。React代码首先会发送一个GET请求到csrfToken端点,从中获取一个令牌。在发送POST请求时,该令牌将设置在头部中。

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/signup/post", SubmitSignupForm).Methods(http.MethodPost, http.MethodOptions)
	r.HandleFunc("/csrfToken", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(csrf.Token(r)))
	})

	r.Use(csrf.Protect(
		[]byte("fff"),
		csrf.Path("/"),
		csrf.Secure(false),
		csrf.TrustedOrigins([]string{"http://localhost:3001/"}),
		csrf.RequestHeader("TOKEN"),
	))

    c := cors.AllowAll()

	http.ListenAndServe(":8000", c.Handler(r))
}

React代码如下:

import React from 'react';
import './App.css';
import useAxios from "axios-hooks";

function App() {
    const [{response: csrfToken}] = useAxios<string>({url: "http://localhost:8000/csrfToken"})
    const [{response}, doRequest] = useAxios<string>({
        url: "http://localhost:8000/signup/post",
        method: "POST"
    }, {manual: true})

    return (
        <div className="App">
            <header className="App-header">
                <h1>hello</h1>
                <h1>csrf: {csrfToken?.data}</h1>
                <h1>Response: {response?.data}</h1>
                <button onClick={e => {
                    doRequest({data: {key: "something"}, headers: {"TOKEN": csrfToken!.data}})
                }}>click
                </button>
            </header>
        </div>
    );
}

export default App;

让我最困惑的是,我可以使用Postman向/csrfToken端点发送请求,并在头部中使用该值。

然而,当我在浏览器中进行相同操作时,我收到一个403错误响应,显示"Forbidden - CSRF token invalid"。

你有什么想法,我做错了什么?

英文:

I'm creating a React application which talks to a backend written in Go. I have setup CSRF using the Gorilla library. The React code will first send a GET request to the csrfToken endpoint where it receives a token. This token is set in the header when sending the POST request.

func main() {
	r := mux.NewRouter()
	r.HandleFunc(&quot;/signup/post&quot;, SubmitSignupForm).Methods(http.MethodPost, http.MethodOptions)
	r.HandleFunc(&quot;/csrfToken&quot;, func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(csrf.Token(r)))
	})

	r.Use(csrf.Protect(
		[]byte(&quot;fff&quot;),
		csrf.Path(&quot;/&quot;),
		csrf.Secure(false),
		csrf.TrustedOrigins([]string{&quot;http://localhost:3001/&quot;}),
		csrf.RequestHeader(&quot;TOKEN&quot;),
	))

    c := cors.AllowAll()

	http.ListenAndServe(&quot;:8000&quot;, c.Handler(r))
}

The React code looks like this:

import React from &#39;react&#39;;
import &#39;./App.css&#39;;
import useAxios from &quot;axios-hooks&quot;;

function App() {
    const [{response: csrfToken}] = useAxios&lt;string&gt;({url: &quot;http://localhost:8000/csrfToken&quot;})
    const [{response}, doRequest] = useAxios&lt;string&gt;({
        url: &quot;http://localhost:8000/signup/post&quot;,
        method: &quot;POST&quot;
    }, {manual: true})

    return (
        &lt;div className=&quot;App&quot;&gt;
            &lt;header className=&quot;App-header&quot;&gt;
                &lt;h1&gt;hello&lt;/h1&gt;
                &lt;h1&gt;csrf: {csrfToken?.data}&lt;/h1&gt;
                &lt;h1&gt;Response: {response?.data}&lt;/h1&gt;
                &lt;button onClick={e =&gt; {
                    doRequest({data: {key: &quot;something&quot;}, headers: {&quot;TOKEN&quot;: csrfToken!.data}})

                }}&gt;click
                &lt;/button&gt;
            &lt;/header&gt;
        &lt;/div&gt;
    );
}

export default App;

The thing that makes me the most confused is that I'm able to send a request with Postman to the /csrfTokenendpoint and use that value with the header.

However, when I do the same in the browser I get a 403 and responds Forbidden - CSRF token invalid.

Any ideas what I have done wrong?

答案1

得分: 1

我对axios-hooks不太熟悉,但是你是否想在你的React代码中执行csrf函数,并像你在doRequest()中那样获取CSRF令牌呢?
在csrf中没有像doRequest()中那样解构第二个属性。

如果在没有第二个属性的情况下执行csrf函数会执行axios函数,那么你可能需要使用await或.then链,因为它可能返回一个Promise。

我认为这个问题可能更与React相关,而Go部分看起来对我来说没问题。

英文:

I'm not familiar with axios-hooks, but don't you want to execute the csrf function in your react code and fetch the CSRF token like you are doing with doRequest()?
There's no second property being destructured in the csrf like in doRequest().

If doing the csrf function without the second property executes the axios function, you may need an await or .then chain since it presumably returns a promise.

I think this question might be more React related than Go which looks fine to me.

答案2

得分: 0

我找到了问题。

我开始通过创建一个更简单的设置的虚拟项目来调试应用程序。在那里,我成功地设置了一切。在了解了这两个应用程序的区别后,我注意到在不工作的应用程序中没有发送 cookie。

经过一段时间,我明白了由于跨域问题,浏览器没有将 cookie 发送到 API。所有这些都在本地运行,而我痛苦的错误是:

localhost != 127.0.0.1

我所需要做的就是将所有使用 localhost 的地方更改为 127.0.0.1。因为浏览器认为这两者是不同的来源,所以不会发送 cookie...

英文:

I figured out the problem.

I started debugging the application by first creating a dummy project with a much simpler setup. There I managed to successully set everything up. While understanding the differences of the two applications I noticed that the cookie was not being sent in the application that was not working.

After some time I understood that the cookies was not being sent from the browser to the API due to cross origin. All of this was running locally, and my painful mistake was:

localhost != 127.0.0.1

All I needed to do was to change all the places where I had used localhost to 127.0.0.1. Since the browser thought the two were of different origins and would not send the cookies...

huangapple
  • 本文由 发表于 2022年1月28日 22:48:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/70895623.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定