C# 关于爬取网站数据遇到csrf-token的分析与解决
作者:yibey 发布时间:2023-07-25 06:25:39
需求
某航空公司物流单信息查询,是一个post请求。通过后台模拟POST HTTP请求发现无法获取页面数据,通过查看航空公司网站后,发现网站使用避免CSRF攻击机制,直接发挥40X错误。
关于CSRF
读者自行百度
网站HTTP请求分析
Headers
Form Data
在head里包含了cookie 与 x-csrf-token formdata 里包含了_csrf (与head里的值是一样的).
这里通过查看该网站的JS源代码发现_csrf 来自于网页的head标签里
猜测cookie与 x-csrf-token是有一定的有效期,并且他们共同作用来防御CSRF攻击。
解决方案
1,首先请求一下该航空公司的网站,获取cookie与_csrf
2,然后C# 模拟http分别在head和formdata里加入如上参数,发起请求
代码
public class CSRFToken
{
string cookie;//用于请求的站点的cookie
List<string> csrfs;//用于请求站点的token的key 以及 value
public CSRFToken(string url)
{
//校验传输安全
if (!string.IsNullOrWhiteSpace(url))
{
try
{
//设置请求的头信息.获取url的host
var _http = new HttpHelper(url);
string cookie;
string html = _http.CreateGetHttpResponseForPC(out cookie);
this.cookie = cookie;
string headRegex = @"<meta name=""_csrf.*"" content="".*""/>";
MatchCollection matches = Regex.Matches(html, headRegex);
Regex re = new Regex("(?<=content=\").*?(?=\")", RegexOptions.None);
csrfs = new List<string>();
foreach (Match math in matches)
{
MatchCollection mc = re.Matches(math.Value);
foreach (Match ma in mc)
{
csrfs.Add(ma.Value);
}
}
}
catch (Exception e)
{
}
}
}
public String getCookie()
{
return cookie;
}
public void setCookie(String cookie)
{
this.cookie = cookie;
}
public List<string> getCsrf_token()
{
return csrfs;
}
}
httpHelper
public string CreatePostHttpResponse(IDictionary<string, string> headers, IDictionary<string, string> parameters)
{
HttpWebRequest request = null;
//HTTPSQ请求
UTF8Encoding encoding = new System.Text.UTF8Encoding();
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(_baseIPAddress) as HttpWebRequest;
request.ProtocolVersion = HttpVersion.Version10;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// request.ContentType = "application/json";
request.UserAgent = DefaultUserAgent;
//request.Headers.Add("X-CSRF-TOKEN", "bc0cc533-60cc-484a-952d-0b4c1a95672c");
//request.Referer = "https://www.asianacargo.com/tracking/viewTraceAirWaybill.do";
//request.Headers.Add("Origin", "https://www.asianacargo.com");
//request.Headers.Add("Cookie", "JSESSIONID=HP21d2Dq5FoSlG4Fyw4slWwHb0-Sl1CG6jGtj7HE41e5f4aN_R1p!-435435446!117330181");
//request.Host = "www.asianacargo.com";
if (!(headers == null || headers.Count == 0))
{
foreach (string key in headers.Keys)
{
request.Headers.Add(key, headers[key]);
}
}
//如果需要POST数据
if (!(parameters == null || parameters.Count == 0))
{
StringBuilder buffer = new StringBuilder();
int i = 0;
foreach (string key in parameters.Keys)
{
if (i > 0)
{
buffer.AppendFormat("&{0}={1}", key, parameters[key]);
}
else
{
buffer.AppendFormat("{0}={1}", key, parameters[key]);
}
i++;
}
byte[] data = encoding.GetBytes(buffer.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
}
HttpWebResponse response;
try
{
//获得响应流
response = (HttpWebResponse)request.GetResponse();
Stream s = response.GetResponseStream();
StreamReader readStream = new StreamReader(s, Encoding.UTF8);
string SourceCode = readStream.ReadToEnd();
response.Close();
readStream.Close();
return SourceCode;
}
catch (WebException ex)
{
response = ex.Response as HttpWebResponse; return null;
}
}
public string CreateGetHttpResponse(out string cookie)
{
HttpWebRequest request = null;
//HTTPSQ请求
UTF8Encoding encoding = new System.Text.UTF8Encoding();
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(_baseIPAddress) as HttpWebRequest;
request.ProtocolVersion = HttpVersion.Version10;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
request.Method = "GET";
request.ContentType = "application/x-www-form-urlencoded";
request.UserAgent = DefaultUserAgent;
HttpWebResponse response;
try
{
//获得响应流
response = (HttpWebResponse)request.GetResponse();
cookie = response.Headers["Set-Cookie"];
Stream s = response.GetResponseStream();
StreamReader readStream = new StreamReader(s, Encoding.UTF8);
string SourceCode = readStream.ReadToEnd();
response.Close();
readStream.Close();
return SourceCode;
}
catch (WebException ex)
{
response = ex.Response as HttpWebResponse;
cookie = "";
return null;
}
}
爬取程序
爬取结果
浏览器结果
注意事项与结论
1,不同的网站,获取cstf的方式不一样,无论怎么做,只要信息传到前台我们都可以有相应的方法来获取。
2,请求时候的http验证可能不一样,测试的某航空公司物流信息的时候,http请求的安全协议是tis12。
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; 还有其他参数比如UserAgent后台可能也会验证
3,基于如上航空公司,发现它的cookie和cstf_token一定时间内不会改变,那么当实际爬取的时候可以考虑缓存cookie以及cstf_token,只有当请求失败的时候,才重新获取
来源:https://www.cnblogs.com/yibey/p/10870472.html
猜你喜欢
- 1. 定义在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。2. 使用的
- 本文实例为大家分享了Java实现计算器设计的具体代码,供大家参考,具体内容如下需求分析目的是实现一个基于Java的可以求解带括号加减乘除表达
- 最近看代码,由于代码的调用层级深度比较多,层层深入到某处时,已经忘记了身处何处,虽然自己可以使用一些画图工具来时序图,但是,这种情况下,自己
- springBoot项目启动多个实例今天碰到一个需求是,将一个服务提供者启动两个实例,一个实例对外,一个实例对内,对内价格有折扣,两个实例通
- SpringBoot @ConditionalOnBean实现原理在SpringBoot1.5.X时判断条件是OR,SpringBoot2.
- 1.导入jar包: <!--jmsTemplate--> <dependency> <
- 在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系。可是有的时候,可能存在多个线程多同一个数据进行操作,这样
- 一、JDK中常见的异常情况1、常见异常总结图2、java中异常分类Throwable类有两个直接子类:(1)Exception:出现的问题是
- 前言什么是mybatis二级缓存?二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace。即,在不同的s
- 在上篇文章,我们介绍了Get方法的设计过程和测试结果,现在我们需要对前面代码进行重构和修改,本篇需要完成以下目标。1)重构Get方法2)如何
- 换了工作要把Java重新捡起来了,这个在大学里用过的语言,虽然不复杂,还是有一些奇怪的地方的。比如static import。Static
- 本文适合有 Java 基础的人群作者:DJL-LankingHelloGitHub 推出的《讲解开源项目》系列。有幸邀请到了亚马逊 + Ap
- 要说this和super就不得不说Java的封装和继承了,首先说封装,这是一种思想,算不上一种技术,核心思想就是将对象的同一行为和状态看成是
- 背景之前和同事讨论一个问题,他们公司调研中发现forEach的速度比for的速度慢,当刚听到这个结论的时候有点诧异。因为之前看过国外的文章和
- 文件比较平常都是用Beyond Compare,可以说离不开的神器,特别是针对代码比较这块,确实挺好用的。不过Beyond Compare平
- 本文实例讲述了C#画笔Pen绘制自定义线的帽子。分享给大家供大家参考。具体如下:using System;using System.Coll
- 之前在使用SpringBoot进行文件上传时,遇到了很多问题。于是在翻阅了很多的博文之后,总算将上传功能进行了相应的完善,便在这里记录下来,
- Swing中的常用按钮在Swing中,常见的按钮组件有JButton,JCheckBox,JRadioButton等,它们都是抽象类Abst
- 使用方法:先把mvcpager.dll引用加入mvc项目中。前台代码前台:@{Layout = null;}@using Webdiyer.
- 一、线程的生命周期线程状态转换图:1、新建状态用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状