惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
About on SuperTechFans
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Help Net Security
Help Net Security
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
O
OpenAI News
美团技术团队
月光博客
月光博客
Apple Machine Learning Research
Apple Machine Learning Research
Schneier on Security
Schneier on Security
Webroot Blog
Webroot Blog
Cyberwarzone
Cyberwarzone
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
T
Tenable Blog
S
Security Affairs
博客园_首页
S
Schneier on Security
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
Spread Privacy
Spread Privacy
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
Vercel News
Vercel News
M
MIT News - Artificial intelligence
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
Martin Fowler
Martin Fowler
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 最新话题
D
DataBreaches.Net
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - Franky
W
WeLiveSecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Check Point Blog
H
Hacker News: Front Page

博客园 - Dr.Wang

mongoDB操作命令,摘自官方helper 让PDF文件也支持书签功能 编码简介 [转]C# 的readonly和const区别 [转]DES加密 java与.net可以相互加密解密两种方法 [转]JAVA与.NET DES加密解密 Ext树控件的制作 [转]SqlServer行列倒置示例 [转]url传递中文的解决方案总结 - Dr.Wang - 博客园 [转]正则表达式基础知识 - Dr.Wang - 博客园 [转]揭开正则表达式的神秘面纱 [转]正则表达式30分钟入门教程 [转]大流量、高并发网站验证码解决方案 [转]通用分页存储过程 [转]sqlserver2005分页查询 匿名方法解决多线程访问控件的问题 - Dr.Wang - 博客园 [转载]C#自定义事件的步骤介绍 [转载]UDP数据包穿透NAT [转载]UDP数据包大小问题
[转]截获asp.net http输出流自己做处理
Dr.Wang · 2011-04-15 · via 博客园 - Dr.Wang

2007-11-5

因项目需要,对每一个访问网站的请求要做原始数据记录,其中要包括几个要素:
1.客户端的IP
2.客户端请求的页面路径
3.客户端发出的请求头
4.服务器返回的正文内容。

在代码设计前分析了一下,前三个都很好解决,对于截获服务器返回的正文,准备用HttpResponse 对象中的Output 和 OutputStream 属性输出信息来解决。

可是在正式编码的过程中,发现Output和OutputStream 并不是想像中可以直接把数据转出取回,耗费了近两天的时间,想尽了一切办法可还是仅仅可以追加内容并无法读取。

在网上查阅到,对于HttpResponse 对象,仅仅可以使用过滤器来对其中将要输出的内容进行修改。
这个过滤器要继承自Stream 类,并要实现其中的虚方法。看来之前企图使用HttpWriter,TextWriter,Stream,HttpStream 这些类来转出数据完全是错误的。

现在有信心来截获服务器返回内容了,说干就干吧!

1.首先要建立一个简易过滤器。
代码如下:
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.IO; 
using System.Web;

/**//// 
/// 定义原始数据EventArgs,便于在截获完整数据后,由事件传递数据
/// 
public class RawDataEventArgs : EventArgs
{
private string sourceCode;

public RawDataEventArgs(string SourceCode)
{
sourceCode = SourceCode; 
}
public string SourceCode
{
get { return sourceCode; }
set { sourceCode = value; }
}
}

//自定义过滤器
public class RawFilter : Stream
{

Stream responseStream; 
long position; 
StringBuilder responseHtml;

/**//// 
/// 当原始数据采集成功后激发。
/// 
public event EventHandler OnRawDataRecordedEvent;

public RawFilter(Stream inputStream)
{
responseStream = inputStream; 
responseHtml = new StringBuilder(); 
}

//实现Stream 虚方法
Filter Overrides#region Filter Overrides

public override bool CanRead
{
get
{
return true; 
}
}

public override bool CanSeek
{
get
{
return true; 
}
}

public override bool CanWrite
{
get
{
return true; 
}
}
public override void Close()
{
responseStream.Close(); 
}

public override void Flush()
{
responseStream.Flush(); 
}

public override long Length
{
get
{
return 0; 
}
}

public override long Position
{
get
{
return position; 
}
set
{
position = value; 
}
}

public override int Read(byte[] buffer, int offset, int count)
{
return responseStream.Read(buffer, offset, count); 
}

public override long Seek(long offset, SeekOrigin origin)
{
return responseStream.Seek(offset, origin); 
}

public override void SetLength(long length)
{
responseStream.SetLength(length); 
}
#endregion

//关键的点,在HttpResponse 输入内容的时候,一定会调用此方法输入数据,所以要在此方法内截获数据
public override void Write(byte[] buffer, int offset, int count)
{
string strBuffer = System.Text.UTF8Encoding.UTF8.GetString(buffer, offset, count);

//采用正则,检查输入的是否有页面结束符
Regex eof = new Regex("", RegexOptions.IgnoreCase);

if (!eof.IsMatch(strBuffer))
{
//页面没有输出完毕,继续追加内容
responseHtml.Append(strBuffer); 
}
else
{
//页面输出已经完毕,截获内容
responseHtml.Append(strBuffer); 
string finalHtml = responseHtml.ToString();

//激发数据已经获取事件
OnRawDataRecordedEvent(this, new RawDataEventArgs(finalHtml));

//继续传递要发出的内容写入流
byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes(finalHtml);

responseStream.Write(data, 0, data.Length); 
}
}
}
至此,过滤器定义完毕了,接下来还需要把这个过滤器装配到HttpResponse 对象中。
为了能够截获整站的aspx 页面输出的内容,我们可以定义一个HttpModule 来完成。
代码如下:


using System; 
using System.Web; 
using System.Collections.Generic; 
using System.Text; 
using System.IO; 
using System.Diagnostics;

public class HttpRawDataModule : IHttpModule
{
IHttpModule 成员#region IHttpModule 成员

public void Dispose()
{

}

public void Init(HttpApplication context)
{
//绑定事件,在对此请求处理过程全部结束后进行过滤操作
context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState); 
}

#endregion

/**//// 
/// 对此HTTP请求处理的过程全部结束
/// 
/// 
/// 
void context_ReleaseRequestState(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;

//这里需要针对ASPX页面进行拦截,测试发现如果不这么做,Wap 访问站点图片容易显示为X,奇怪
string[] temp = application.Request.CurrentExecutionFilePath.Split(''.''); 
if (temp.Length > 0 && temp[temp.Length - 1].ToLower() == "aspx")
{
//装配过滤器
application.Response.Filter = new RawFilter(application.Response.Filter);

//绑定过滤器事件
RawFilter filter = (RawFilter)application.Response.Filter; 
filter.OnRawDataRecordedEvent += new EventHandler(filter_OnRawDataRecordedEvent); 
}
}

/**//// 
/// 当原始数据采集到以后,入库 
/// 
/// 
/// 
void filter_OnRawDataRecordedEvent(object sender, RawDataEventArgs e)
{
string allcode = e.SourceCode; 
WapSite.SiteDataClass wapdata = new WapSite.SiteDataClass(); 
wapdata.WriteRawDataLog(allcode); 
}
}

HttpModule 准备完毕,也装配上了过滤器,接下来还需要在配置文件中配置HttpModules配置节 ,把自定义的HttpModule 加入到HTTP处理管道中。
在Web.config 中增加配置节如下:

测试成功,能准确的获得服务器向客户端输出的HTML内容。

其中,在过滤器中,可以直接对即将要输出的内容做 对于字符串的任意处理。

而且采用这样的方式来对站点即将输出的内容做修改和采集,可以通过修改配置文件,随时打开和关闭,有很强的优越性和灵活性还有重用性。

记得看到过很多需要产生静态页面的网站,都是通过代码HttpWebRequest 向自己请求并记录返回的代码产生静态页面,不知道我当前介绍的方法是否更好写,比如需要产生静态页面时,不管是谁发出请求,由服务器检查自己是否有静态页面,否则产生静态页面,并转向。给出引子,希望大家还是自己开阔思路比较好。

这里我还想到一个额外的使用场景,比如入侵到一台支撑IIS 的服务器,上传自定义的过滤器和自定义的HttpModule 库,修改对方站点内的配置文件使之生效,就可以轻松做到窃取客户端输入内容和输出内容。不过修改配置文件不知道会不会让人容易发觉呀???