使用c#/ ASP.NET以编程方式伪造登录到网站

因此,我正在尝试模拟多个登录,同时在我们的公司网站上生成exception,以便测试我们的日志框架(我们认为可能存在线程同步问题)。 无论如何,所以我需要以编程方式登录我们的网站。 这是我到目前为止所拥有的:

// Block 1 Uri url = new Uri("http://withheld"); HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; request.Method = "GET"; HttpWebResponse response = request.GetResponse() as HttpWebResponse; string viewState = string.Empty; string previousPage = string.Empty; string eventValidation = string.Empty; using (StreamReader reader = new StreamReader(response.GetResponseStream())) { string strResponse = reader.ReadToEnd(); viewState = HttpUtility.UrlEncode(GetTagValue(strResponse, "__VIEWSTATE")); previousPage = HttpUtility.UrlEncode(GetTagValue(strResponse, "__PREVIOUSPAGE")); eventValidation = HttpUtility.UrlEncode(GetTagValue(strResponse, "__EVENTVALIDATION")); } // Block 2 string username = "user01"; string password = "password99"; HttpWebRequest request2 = WebRequest.Create(url) as HttpWebRequest; request2.KeepAlive = true; request2.Method = "POST"; request2.ContentType = "application/x-www-form-urlencoded"; string postData = string.Format("__LASTFOCUS=&ctrlCreateNewPassword_scriptManagerMaster_HiddenField=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE={0}&__PREVIOUSPAGE={1}&__EVENTVALIDATION={2}&UserName={3}&Password={4}&LoginButton=Log+in", new string[] { viewState, previousPage, eventValidation, username, password}); byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(postData); request2.ContentLength = dataBytes.Length; using (Stream postStream = request2.GetRequestStream()) { // Here's the problem postStream.Write(dataBytes, 0, dataBytes.Length); } HttpWebResponse httpResponse = request2.GetResponse() as HttpWebResponse; // At this point httpResponse.Cookies is null // I believe it's because the line above has actually initiated another // request/response which DOES NOT include the authentication cookie. // See fiddler output below to understand why I think that. // Block 3 //Uri url2 = new Uri("http://Withheld/GenerateException.aspx"); //http = WebRequest.Create(url2) as HttpWebRequest; //http.CookieContainer = new CookieContainer(); //http.CookieContainer.Add(httpResponse.Cookies); //HttpWebResponse httpResponse2 = http.GetResponse() as HttpWebResponse; 

看起来相当简单吧? 好吧它不起作用。 我不知道我是否需要viewState和whatnot或not,但我想我会模仿常规浏览器尽可能接近的地方。

接近我可以告诉我发生了什么是这样的:

  1. 我们用简单的GET命中了页面。 这给了我们viewstate等,它被解析出来包含在下面的请求中。
  2. 我们现在使用postStream.Write()将viewstate,username,password等发布到服务器。 此时服务器使用身份validationcookie进行响应,并将我们转发到/Default.aspx。
  3. 现在我们执行reqest2.GetResponse(),但是没有获得将我们转发给/default.aspx的响应并且拥有身份validationcookie,看起来这行实际上导致了另一个请求来获取/default.aspx中的资源。 问题是httpWebResponse不包括我们下一个请求所需的身份validationcookie(当前已被注释掉)。

为什么? 为什么这个在这个庄园中表现,我该如何正确处理它。 这是fiddler的输出,以进一步解释发生了什么:

块1生成此请求/响应请求标头:

 GET http://withheld/Login.aspx HTTP/1.1 Host: withheld Connection: Keep-Alive 

响应标题:

 HTTP/1.1 200 OK Connection: close Date: Mon, 04 Feb 2013 16:37:37 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Set-Cookie: .EXTASPXAUTH=; expires=Tue, 12-Oct-1999 04:00:00 GMT; path=/; HttpOnly Cache-Control: private, no-cache="Set-Cookie" Content-Type: text/html; charset=utf-8 Content-Length: 16975 Response is the actual login webpage. Omitted for obvious reasons. 

单步执行代码,在调用postStream.Write之后立即生成此请求/响应:

请求:

 POST http://Withheld/Login.aspx HTTP/1.1 Content-Type: application/x-www-form-urlencoded Host: withheld Content-Length: 2109 Expect: 100-continue __LASTFOCUS=&ctrlCreateNewPassword_scriptManagerMaster_HiddenField=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%%%3d&__PREVIOUSPAGE=1aYW5DqTKrT4ieGPkHcnrQLIq8lEcSIVkql1EugwSQNV_5102t5D7QDmOnuQFA4Tz9Mh5-CEYpkRngMROFFeeAG12Ss1&__EVENTVALIDATION=%2fwEWCQKKr%2bXcBgKvruq2CALSxeCRDwL%2bjNCfDwKH8YSKBgKN6O7XCwKz9P38DALl3I74DwLWxI74D6Nz%2f2bCBFC%2bM9glZmEyM%2byOCTZg&UserName=user01&Password=password99&LoginButton=Log+in 

响应:

 HTTP/1.1 302 Found Connection: close Date: Mon, 04 Feb 2013 16:36:55 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Location: https://stackoverflow.com/Default.aspx?locale=en Set-Cookie: .EXTASPXAUTH=65BB5BFDD274F730E26CAEAAEB417792A764E7B8E8C6C9AC8C47FA97EF35DFACF551A53EAA6EA67D868C8A9BF55EBA758A5E724C58269028EE48F56268A204CBED19B60FC1AF58892989D9546202C037E97BF0EEE6A6281FF5EEA461BC30C5C7A71DFD64027AEB796D3FD21AE97ECFB16FF0F95C; path=/; HttpOnly Cache-Control: private, no-cache="Set-Cookie" Content-Type: text/html; charset=utf-8 Content-Length: 140 Object moved 

Object moved to here.

请注意,上述响应包括validationcookie。 现在我们运行以下代码行以获取该cookie:

 HttpWebResponse httpResponse = request2.GetResponse() as HttpWebResponse; 

但是在fiddler中生成以下请求/响应:

请求:

 GET http://withtheldhttps://stackoverflow.com/Default.aspx?locale=en HTTP/1.1 Content-Type: application/x-www-form-urlencoded Host: withheld 

响应:

 HTTP/1.1 302 Found Connection: close Date: Mon, 04 Feb 2013 16:37:38 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Location: /Login.aspx?ReturnUrl=%2fDefault.aspx%3flocale%3den&locale=en Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 182 Object moved 

Object moved to here.

我相信这是httpResponse现在包含的响应。 如何在登录完成后实际获取cookie以请求另一个受保护的页面?

谢谢!

事实certificate我在这里有两个问题。 一个是我需要称之为:

 request.AllowAutoRedirect = false 

这使得框架不会仅仅跳过包含身份validationcookie的响应,而实际上会回放我们感兴趣的响应。

另一个问题是您必须创建CookieContainer的新实例并将其分配给请求。 没有做过Response.Cookies不包含cookie。 一旦您分配了自己的容器,就会在响应完成后填充它。 我不知道为什么。

登录时,身份validation令牌将作为cookie从服务器发送到您的客户端。 您需要存储此cookie,然后在将来的每个请求中重新发送它。 重新发送cookie告诉服务器您已被认证为某个用户。

要获取登录后发送的cookie,请执行以下操作:

 HttpCookieCollection loginResponseCookies = Response.Cookies; 

此集合将包括身份validationcookie,任何会话cookie等。

然后,只需在每个后续请求中重新发送这些cookie,服务器就会对您进行身份validation。

 foreach(HttpCookie loginResponseCookie in loginResponseCookies) { Response.Cookies.Add(loginResponseCookie); }