上周完成了一个从ASP.NET WebForm 开发的站点抓包的功能。该功能要求使用该网点内的帐号通过我们自己的程序获取网站内的数据。其间使用了HttpWebRequest 进行抓包。具体的抓包过程就不重点讨论了。旨在和大家分享一下我在抓包过程中对ViewState 在 ASP.NET WebForm 中的作用有了进一步的了解。如果存在不足之处,希望您能指出。
为了模拟Http POST/GET 我们用VS建立两个工程,截图如下:
注:第一个工程是一个简单的ASP.NET Web Form 程序,第二个是模拟Web Form 的 WinForm 程序。
WebApplication1 执行如下:
两个服务器端控件 DropDownList 和 Button 服务器端相应事件如下:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { if (DropDownList1.SelectedValue == "Two") { lblInfor.Text = "Two"; } else { lblInfor.Text = "One"; } }
功能代码非常简单,Button1被单击后显示dropdownlist 的文本值:
Webform介绍完,剩下就是用WinForm 通过HTTP POST/GET来模拟Web Form 程序,程序运行界面如下:
这里的OnePost 与TwoPost 分别模拟WebForm中 Post 按钮Click功能。
贴出模拟的核心代码:PostByWebRequest 函数:
private void PostByWebRequest(string strPostValue) { try { string URI = "http://localhost:2026/webform1.aspx/"; HttpWebRequest request = WebRequest.Create(URI) as HttpWebRequest; request.Method = "GET"; request.KeepAlive = true; request.CookieContainer = cookieContainer; HttpWebResponse response = request.GetResponse() as HttpWebResponse; System.IO.Stream responseStream = response.GetResponseStream(); System.IO.StreamReader reader = new System.IO.StreamReader(responseStream, Encoding.UTF8); //返回的页面html文本 string srcString = reader.ReadToEnd(); //VeiwState string viewStateFlag = "id=\"__VIEWSTATE\" value=\""; int len1 = srcString.IndexOf(viewStateFlag) + viewStateFlag.Length; int len2 = srcString.IndexOf("\"", len1); string viewState = srcString.Substring(len1, len2 - len1); //EventValidation string eventValidationFlag = "id=\"__EVENTVALIDATION\" value=\""; len1 = srcString.IndexOf(eventValidationFlag) + eventValidationFlag.Length; len2 = srcString.IndexOf("\"", len1); string eventValidation = srcString.Substring(len1, len2 - len1); //编码 viewState = System.Web.HttpUtility.UrlEncode(viewState); eventValidation = System.Web.HttpUtility.UrlEncode(eventValidation); //这里可以通过抓包工具获得poststring.记得中文需要UrlEncode编码。 string formatString = "DropDownList1={0}&Button1={1}&__VIEWSTATE={2}&__EVENTVALIDATION={3}"; string postString = string.Format(formatString, strPostValue, "Do PostBack", viewState, eventValidation); byte[] postData = Encoding.UTF8.GetBytes(postString); URI = "http://localhost:2026/webform1.aspx/"; //POST request = WebRequest.Create(URI) as HttpWebRequest; request.Method = "POST"; request.KeepAlive = false; request.ContentType = "application/x-www-form-urlencoded"; request.CookieContainer = cookieContainer; request.ContentLength = postData.Length; System.IO.Stream outputStream = request.GetRequestStream(); outputStream.Write(postData, 0, postData.Length); outputStream.Close(); response = request.GetResponse() as HttpWebResponse; responseStream = response.GetResponseStream(); reader = new System.IO.StreamReader(responseStream, Encoding.UTF8); srcString = reader.ReadToEnd(); } catch (Exception ex) { string msg = ex.Message; MessageBox.Show(ex.Message); } }
PostByWebRequest函数调用如下:
OnePost 按钮单击执行: PostByWebRequest("One");
TwoPost 按钮单击执行: PostByWebRequest("Two");
注:如果在PostByWebRequest函数的第31行,不传入ViewState或
EVENTVALIDATION,WinForm内的两个按钮均不能成功模拟WebForm。最终模拟的正确效果是:预先
在WebForm 的 Button_Click内设置断点,接着
点击WinForm内的两个按钮,VS会自动截获到该断点设置。说明我们顺利模拟了WebForm的POST的机制。如果点击
TwoPost 按钮时,WebForm 服务器端不但会执行Post按钮事件还会执行DropDownlist 的SelectedIndexChanged事件。为什么会执行到DropDownlist 的SelectedIndexChanged事件呢?这一切都归功于ViewState。它记录了WebForm的表单内容从而做出了相应的处理。所以WebForm 的 ViewState 机制还是很强大的。让我们用事件机制去开发Web程序。同时ViewState机制让我们的web form 程序更难被“爬虫”获取程序内容,想用程序Post WebForm 就必须传入传入ViewState 。否则POST不会返回正确的页面内容。