2014-01-20 46 views
0

我想從需要登錄的站點自動備份網站內容。我嘗試通過模擬POST請求來登錄。但我得到的錯誤:使用Go/Python登錄到使用CSRF令牌的網站

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 
} 

的CSRF令牌,我得到通過獲取登錄頁面並掃描它命名爲signin[_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 
} 

我並不需要使用去,只是因爲我最熟悉。使用python也可能是一個解決方案,但我沒有更多的運氣。

+0

您可以使用python請求並使用會話來存儲所有cokies,http://stackoverflow.com/questions/12737740/python-requests-and-persistent-sessions –

+0

如果您使用Go,您可能需要創建一個cookie罐子爲您的客戶。如果http.Client.Jar爲零,則Cookie不會在請求中發送,並且在響應中被忽略。 –

+0

是的,我有一種感覺,它必須是一個cookie問題,因爲如果不使用cookie,服務器將不知道第二個請求是從我這裏得到的,可能會認爲我欺騙了webclient或其他東西。我會盡力弄清楚如何在Go中使用cookies。 –

回答

2

問題是Go 1.2不會自動爲它的HTTP請求使用cookie jar。第一個請求是從登錄頁面獲取CSRF令牌。第二個請求是使用該CSRF令牌POST登錄。但由於在第二個請求上沒有會話cookie被附加到HTTP頭上,服務器不知道它是試圖登錄的程序。因此服務器認爲這是一個CSRF嘗試(您從其他地方選擇了CSRF令牌並試圖重用它)。

因此,要獲取登錄頁面並提取CSRF令牌,我們首先創建自己的客戶端對象。否則,我們無處附上餅乾罐。 http.PostForm確實給訪問餅乾罐:

client = &http.Client{} 

創建authenticated http client requests from golang描述cookie罐。這是更容易安裝和調試比官方:http://golang.org/pkg/net/http/cookiejar/餅乾罐

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) 

然後登錄,我們重用與它相連的餅乾罐的客戶對象:

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讓我走上正軌。

0

您可以使用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")