python - 使用 Go/Python 使用 CSRF token 登录站点

标签 python authentication go csrf

我想从需要登录的站点自动备份 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/

相关文章:

python - Pandas - 解包不同长度的元组列表列

python - 在 PyQt 中的菜单栏下方显示图像

python - 更改自动插入到 tkinter 小部件中的文本的颜色

amazon-web-services - 使用 Cognito 防止多个同时登录

php - 在哪里可以找到创建单向注册和登录系统的教程?

http - Golang - 检查错误和推迟操作的正确顺序是什么?

post - 如何通过POST发送参数

go - 什么是 Golang 结构字段命名约定?

python - 使用 turtle 模块 exitonclick()

database - Azure 上的主数据库创建用户失败