在 Web 开发中,一般须要对前端(front-end)传到后端(back-end)的数据进行过滤和校验,以防范诸如 SQL 注入、XSS 注入之类的攻击。
在 Java 中,经过继承 HttpServletRequestWrapper 类可从新包装当前请求(Http Request)并将其替换,它的实现以下:前端
public class RequestWrapper extends HttpServletRequestWrapper { private String AMP = "&"; private String queryString; public RequestWrapper(HttpServletRequest request, String queryString) { super(request); this.queryString = queryString; } public String getQueryString() { String query = null; if (super.getQueryString() != null) { query = super.getQueryString() + AMP + this.queryString; } else { query = this.queryString; } return query; } } public class RequestHandler{ public void changeRequest{ RequestWrapper reqWrapper = new RequestWrapper(httpRequest, newQueryString() ); FilterChain.doFilter(reqWrapper, servletResponse); // this FilterChain guy helps to replace the old request to // new request to runtime } }
然而,Asp.NET 中并无相似的包装器实现,一般的作法是在每个请求经过(ProcessRequest)后再进行合法性校验,它致使的问题是每一个请求 Action 都须要重复调用过滤方法来过滤请求参数。这显然冗余且麻烦得不太合理。java
在 IIS 7.0+ 中,能够经过 HttpModule
来实现。web
下面列举了一些可能须要提早了解的知识点c#
BeginRequest
事件中进行设置,这是请求验证和 url 映射以后的第一个事件。下面以在 .Net MVC 中配置示例后端
<?xml version="1.0" encoding="utf-8"?> <configuration> // ignore other configuration <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <modules runAllManagedModulesForAllRequests="true"> <add name="httpModule" type="HttpRequestFilterModule" /> </modules> </system.webServer> </configuration>
HttpRequestFilterModule
using MvcApplication1.Filter; using System.Web; public class HttpRequestFilterModule : IHttpModule { public void Dispose() { throw new NotImplementedException(); } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(Application_BeginRequest); } public void Application_BeginRequest(object sender, EventArgs args) { HttpContext context = HttpContext.Current; HttpRequest request = context.Request; // 仅过滤 POST 请求 if (context.Request.HttpMethod != "POST") { return; } var requestCallback = new Func<string, string>(content => { // may modify request content here return "The request content is modified."; }); context.Request.Filter = new RequestFilter(context.Request.Filter, context.Request.ContentEncoding, requestCallback); } }
RequestFilter.csapi
using System; using System.IO; using System.Text; namespace MvcApplication1.Filter { public class RequestFilter : Stream { //临时缓冲区用于优化加载 private MemoryStream ms; //处理原始输出流 private Stream _stream; //响应的编码方式 private Encoding _encoding; //回调delegate private Func<string, string> _callback; public RequestFilter(Stream stream, Encoding encoding, Func<string, string> callback) { _stream = stream; _encoding = encoding; _callback = callback; } public override void Flush() { ms.Flush(); } public override long Seek(long offset, SeekOrigin origin) { return ms.Seek(offset, origin); } public override void SetLength(long value) { ms.SetLength(value); } public override int Read(byte[] buffer, int offset, int count) { if (ms == null) { var sr = new StreamReader(_stream, _encoding); string content = sr.ReadToEnd(); //回调执行 content = _callback(content); byte[] bytes = _encoding.GetBytes(content); ms = new MemoryStream(); ms.Write(bytes, 0, bytes.Length); ms.Seek(0, SeekOrigin.Begin); } return ms.Read(buffer, offset, count); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } public override bool CanRead { get { return true; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return false; } } public override long Length { get { return ms.Length; } } public override long Position { get { return ms.Position; } set { throw new NotSupportedException(); } } } }
若是正常工做,访问下面 Get Action, 将获得
The request content is modified.
的输出结果。
public class HomeController : Controller { [HttpPost] public ActionResult Get() { string requestBody = string.Empty; using (StreamReader reader = new StreamReader(Request.InputStream)) { requestBody = reader.ReadToEnd(); } return Content(requestBody); } }