我想从需要登录的站点自动备份 Web 内容。我尝试通过模拟 POST 请求登录。但是我得到了错误:
csrf token: CSRF attack detected
以下是我使用的代码的一些摘录:
func postLoginForm(csrfToken string) {
values := make(url.Values)
values.Set("signin[username]", "myusername")
values.Set("signin[password]", "mypassword")
values.Set("signin[_csrf_token]", csrfToken)
resp, err := http.PostForm("https://spwebservicebm.reaktor.no/admin/nb", values)
dumpHTTPResponse(resp) // show response to STDOUT
}
我通过获取登录页面并在其中扫描名为 signin[_csrf_token]
的隐藏输入字段获得的 csrf token 。执行此操作的代码的重要部分如下:
// Finds input field named signin[_csrf_token] and returns value as csrfToken
func handleNode(n *html.Node) (csrfToken string, found bool) {
if n.Type == html.ElementNode && n.Data == "input" {
m := make(map[string]string)
for _, attr := range n.Attr {
m[attr.Key] = attr.Val
}
if m["name"] == "signin[_csrf_token]" {
return m["value"], true
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
if csrfToken, found = handleNode(c); found {
return
}
}
return "", false
}
我不需要使用 Go,那只是因为我最熟悉它。使用 python 也可能是一种解决方案,但我没有更多的运气。
最佳答案
问题在于 Go 1.2 不会自动为其 HTTP 请求使用 cookie jar。第一个请求是从登录页面获取 CSRF token 。第二个请求是使用该 CSRF token POST 登录。但是由于没有 session cookie 附加到第二个请求的 HTTP header ,服务器不知道它是同一个程序试图登录。因此服务器认为这是一次 CSRF 尝试(您从其他地方选择了 CSRF token 并尝试重用它)。
因此,为了获取登录页面并提取 CSRF token ,我们首先创建自己的客户端对象。否则我们无处可附加 cookies jar 。 http.PostForm
确实允许访问 cookie jar:
client = &http.Client{}
创建 authenticated http client requests from golang 中描述的 cookie Jar .这比官方更容易设置和调试:http://golang.org/pkg/net/http/cookiejar/ cookies jar
jar := &myjar{}
jar.jar = make(map[string] []*http.Cookie)
client.Jar = jar
resp, err := client.Get("https://spwebservicebm.reaktor.no/admin")
doc, err := html.Parse(resp.Body)
然后为了登录,我们重用客户端对象和附加的 cookie jar:
values := make(url.Values)
values.Set("signin[username]", "myusername")
values.Set("signin[password]", "mypassword")
values.Set("signin[_csrf_token]", csrfToken)
resp, err := client.PostForm("https://spwebservicebm.reaktor.no/admin/login", values)
您会注意到代码几乎与问题中的代码相同,只是我们使用 client.PostForm
而不是 http.PostForm
。
感谢 dommage 和对 authenticated http client requests from golang 的回答让我走上正轨。
关于python - 使用 Go/Python 使用 CSRF token 登录站点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21232665/