使用Go/Python使用CSRF令牌登录站点

2024-10-01 17:31:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我想从需要登录的网站自动备份网页内容。我试图通过模拟POST请求登录。但我得到了一个错误:

csrf token: CSRF attack detected

以下是我使用的代码的一些摘录:

^{pr2}$

我通过获取登录页面并扫描它以查找名为signin[_csrf_token]的隐藏输入字段得到的csrf令牌。为此,代码的重要部分如下:

// 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
}

我不需要用围棋,那是因为我对围棋最熟悉。使用python也可以是一个解决方案,但我没有更多的运气。在


Tags: 代码tokenforinputstringreturnifvalue
2条回答

您可以使用beautifulsoup获取令牌并将其存储在头中或发送到服务器。你可以这样做:

from requests import session
from bs4 import BeautifulSoup

def authent(self):
    ld('trying to get token...')
    r = self.session.get(BASE_URL, headers=FF_USER_AGENT)
    soup = BeautifulSoup(r.content)
    elgg_token = soup.select('input[name="__elgg_token"]')[0]["value"]
    elg_ts = soup.select('input[name="__elgg_ts"]')[0]["value"]
    payload["__elgg_token"] = elgg_token # I sent it to the server...
    payload["__elgg_ts"] = elg_ts
    r = self.session.post(LOGIN_URL, data=payload, headers=FF_USER_AGENT)
    if r.url != DASHBOARD_URL:
      raise AuthentError("Error")

问题是Go1.2不会自动为其HTTP请求使用cookiejar。第一个请求是从登录页面获取CSRF令牌。第二个请求是使用CSRF令牌发布登录。但是,由于在第二个请求上没有将会话cookie附加到HTTP头上,服务器不知道它是试图登录的同一个程序。因此,服务器认为这是CSRF尝试(您从其他地方选择CSRF令牌并尝试重用它)。在

所以要获取登录页面并提取CSRF令牌,我们首先创建自己的客户机对象。否则我们就没地方装饼干罐了。http.PostForm确实允许访问cookie jar:

client = &http.Client{}

创建一个在authenticated http client requests from golang中描述的cookie Jar。这比官方的:http://golang.org/pkg/net/http/cookiejar/cookiejar更容易安装和调试

^{pr2}$

然后,为了登录,我们重用客户端对象并附加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和response to authenticated http client requests from golang让我走上正轨。在

相关问题 更多 >

    热门问题