在 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); } }