asp.net利用HttpModule實(shí)現(xiàn)防sql注入
更新時(shí)間:2009年12月24日 01:24:49 作者:
關(guān)于sql注入,已經(jīng)被很多人討論過(guò)了。這篇沒(méi)有新意功能也不夠通用,nnd,不想引起口水,就是覺(jué)得簡(jiǎn)單而且思路有參考性才貼出來(lái)。
1、新建一個(gè)類(lèi),實(shí)現(xiàn)IHttpModule接口
代碼
public class SqlHttpModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
}
在實(shí)現(xiàn)接口的Init方法時(shí),我們選擇了AcquireRequestState事件,為什么不是Begin_Request事件呢?這是因?yàn)槲覀冊(cè)谔幚淼臅r(shí)候可能用的session,而B(niǎo)egin_Request事件執(zhí)行的時(shí)候還沒(méi)有加載session狀態(tài)(關(guān)于HttpModule可以參考這一篇)。
2、對(duì)網(wǎng)站提交的數(shù)據(jù)進(jìn)行處理
(1)、GET方式
代碼
//url提交數(shù)據(jù) get方式
if (context.Request.QueryString != null)
{
for (int i = 0; i < context.Request.QueryString.Count; i++)
{
key = context.Request.QueryString.Keys[i];
value = context.Server.UrlDecode(context.Request.QueryString[key]);
if (!FilterSql(value))
{
throw new Exception("QueryString(GET) including dangerous sql key word!");
}
}
}
(2)、POST方式
代碼
//表單提交數(shù)據(jù) post方式
if (context.Request.Form != null)
{
for (int i = 0; i < context.Request.Form.Count; i++)
{
key = context.Request.Form.Keys[i];
if (key == "__VIEWSTATE") continue;
value = context.Server.HtmlDecode(context.Request.Form[i]);
if (!FilterSql(value))
{
throw new Exception("Request.Form(POST) including dangerous sql key word!");
}
}
}
完整代碼:
代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
namespace DotNet.Common.WebForm
{
/// <summary>
/// 簡(jiǎn)單防止sql注入
/// </summary>
public class SqlHttpModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
/// <summary>
/// 處理sql注入
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void context_AcquireRequestState(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
try
{
string key = string.Empty;
string value = string.Empty;
//url提交數(shù)據(jù) get方式
if (context.Request.QueryString != null)
{
for (int i = 0; i < context.Request.QueryString.Count; i++)
{
key = context.Request.QueryString.Keys[i];
value = context.Server.UrlDecode(context.Request.QueryString[key]);
if (!FilterSql(value))
{
throw new Exception("QueryString(GET) including dangerous sql key word!");
}
}
}
//表單提交數(shù)據(jù) post方式
if (context.Request.Form != null)
{
for (int i = 0; i < context.Request.Form.Count; i++)
{
key = context.Request.Form.Keys[i];
if (key == "__VIEWSTATE") continue;
value = context.Server.HtmlDecode(context.Request.Form[i]);
if (!FilterSql(value))
{
throw new Exception("Request.Form(POST) including dangerous sql key word!");
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 過(guò)濾非法關(guān)鍵字,這個(gè)可以按照項(xiàng)目靈活配置
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private bool FilterSql(string key)
{
bool flag = true;
try
{
if (!string.IsNullOrEmpty(key))
{
//一般配置在公共的文件中,如xml文件,txt文本等等
string sqlStr = "insert |delete |select |update |exec |varchar |drop |creat |declare |truncate |cursor |begin |open|<-- |--> ";
string[] sqlStrArr = sqlStr.Split('|');
foreach (string strChild in sqlStrArr)
{
if (key.ToUpper().IndexOf(strChild.ToUpper()) != -1)
{
flag = false;
break;
}
}
}
}
catch
{
flag = false;
}
return flag;
}
}
}
3、在web項(xiàng)目中應(yīng)用
只要在web.config的httpModules節(jié)點(diǎn)下面添加如下配置即可。
<httpModules>
<add name="SqlHttpModule" type="DotNet.Common.WebForm.SqlHttpModule, DotNet.Common.WebForm"></add>
</httpModules>
需要說(shuō)明的是,這個(gè)防止sql注入的方法在特定的小項(xiàng)目中還是很簡(jiǎn)潔高效的,但是不通用,通常我們都是選擇參數(shù)化(利用orm或者ado.net的參數(shù)化)方式防止sql注入。
附:asp.net在網(wǎng)頁(yè)頭部引入js腳本的簡(jiǎn)單方法
asp.net開(kāi)發(fā)少不了JavaScript的輔助。在通常項(xiàng)目中,js文件都組織在一個(gè)公共目錄如js文件夾下。隨著項(xiàng)目的深入,你會(huì)發(fā)現(xiàn)js腳本文件越來(lái)越多,公共的腳步庫(kù)越來(lái)越龐大。實(shí)際使用的時(shí)候,我們通常都是在頁(yè)面中通過(guò) <script src="..." type="text/javascript" >形式引入js文件,而且引入的越來(lái)越多。下面我們就來(lái)簡(jiǎn)單討論在每個(gè)頁(yè)面引入公共腳本庫(kù)的統(tǒng)一方式,而不用每個(gè)頁(yè)面都是很多<script src="..." type="text/javascript" >的形式。
和我們以前的做法一樣,定義一個(gè)頁(yè)面基類(lèi)叫BasePage,事件和方法如下:
Code
using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Reflection;
using System.Text;
using System.IO;
namespace DotNet.Common.WebForm
{
using DotNet.Common.Model;
using DotNet.Common.Util;
public class BasePage : System.Web.UI.Page
{
public BasePage()
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
AddHeaderJs();//向網(wǎng)頁(yè)頭部添加js等文件
}
#region 網(wǎng)頁(yè)頭添加通用統(tǒng)一js文件
private void AddHeaderJs()
{
string jsPath = "~/js/";
string filePath = Server.MapPath(jsPath);
Literal lit = new Literal();
StringBuilder sb = new StringBuilder();
if (!Directory.Exists(filePath))
throw new Exception("路徑不存在");
List<string> listJs = new List<string>();
foreach (var item in Directory.GetFiles(filePath, "*.js", SearchOption.TopDirectoryOnly))
{
listJs.Add(Path.GetFileName(item));
}
foreach (var jsname in listJs)
{
sb.Append(ScriptInclude(jsPath + jsname));
}
lit.Text = sb.ToString();
Header.Controls.AddAt(1, lit);
}
private string ResolveHeaderUrl(string relativeUrl)
{
string url = null;
if (string.IsNullOrEmpty(relativeUrl))
{
url = string.Empty;
}
else if (!relativeUrl.StartsWith("~"))
{
url = relativeUrl;
}
else
{
var basePath = HttpContext.Current.Request.ApplicationPath;
url = basePath + relativeUrl.Substring(1);
url = url.Replace("http://", "/");
}
return url;
}
private string ScriptInclude(string url)
{
if (string.IsNullOrEmpty(url))
throw new Exception("路徑不存在");
string path = ResolveHeaderUrl(url);
return string.Format(@"<script src='{0}' type='text/javascript'></script>", path);
}
#endregion
}
}
這樣就簡(jiǎn)單地解決了引入公共js的問(wèn)題。同樣的原理,你也可以引入其他類(lèi)型的文件,如css等。
demo下載
代碼
復(fù)制代碼 代碼如下:
public class SqlHttpModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
}
在實(shí)現(xiàn)接口的Init方法時(shí),我們選擇了AcquireRequestState事件,為什么不是Begin_Request事件呢?這是因?yàn)槲覀冊(cè)谔幚淼臅r(shí)候可能用的session,而B(niǎo)egin_Request事件執(zhí)行的時(shí)候還沒(méi)有加載session狀態(tài)(關(guān)于HttpModule可以參考這一篇)。
2、對(duì)網(wǎng)站提交的數(shù)據(jù)進(jìn)行處理
(1)、GET方式
代碼
復(fù)制代碼 代碼如下:
//url提交數(shù)據(jù) get方式
if (context.Request.QueryString != null)
{
for (int i = 0; i < context.Request.QueryString.Count; i++)
{
key = context.Request.QueryString.Keys[i];
value = context.Server.UrlDecode(context.Request.QueryString[key]);
if (!FilterSql(value))
{
throw new Exception("QueryString(GET) including dangerous sql key word!");
}
}
}
(2)、POST方式
代碼
復(fù)制代碼 代碼如下:
//表單提交數(shù)據(jù) post方式
if (context.Request.Form != null)
{
for (int i = 0; i < context.Request.Form.Count; i++)
{
key = context.Request.Form.Keys[i];
if (key == "__VIEWSTATE") continue;
value = context.Server.HtmlDecode(context.Request.Form[i]);
if (!FilterSql(value))
{
throw new Exception("Request.Form(POST) including dangerous sql key word!");
}
}
}
完整代碼:
代碼
復(fù)制代碼 代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
namespace DotNet.Common.WebForm
{
/// <summary>
/// 簡(jiǎn)單防止sql注入
/// </summary>
public class SqlHttpModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
/// <summary>
/// 處理sql注入
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void context_AcquireRequestState(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
try
{
string key = string.Empty;
string value = string.Empty;
//url提交數(shù)據(jù) get方式
if (context.Request.QueryString != null)
{
for (int i = 0; i < context.Request.QueryString.Count; i++)
{
key = context.Request.QueryString.Keys[i];
value = context.Server.UrlDecode(context.Request.QueryString[key]);
if (!FilterSql(value))
{
throw new Exception("QueryString(GET) including dangerous sql key word!");
}
}
}
//表單提交數(shù)據(jù) post方式
if (context.Request.Form != null)
{
for (int i = 0; i < context.Request.Form.Count; i++)
{
key = context.Request.Form.Keys[i];
if (key == "__VIEWSTATE") continue;
value = context.Server.HtmlDecode(context.Request.Form[i]);
if (!FilterSql(value))
{
throw new Exception("Request.Form(POST) including dangerous sql key word!");
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 過(guò)濾非法關(guān)鍵字,這個(gè)可以按照項(xiàng)目靈活配置
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private bool FilterSql(string key)
{
bool flag = true;
try
{
if (!string.IsNullOrEmpty(key))
{
//一般配置在公共的文件中,如xml文件,txt文本等等
string sqlStr = "insert |delete |select |update |exec |varchar |drop |creat |declare |truncate |cursor |begin |open|<-- |--> ";
string[] sqlStrArr = sqlStr.Split('|');
foreach (string strChild in sqlStrArr)
{
if (key.ToUpper().IndexOf(strChild.ToUpper()) != -1)
{
flag = false;
break;
}
}
}
}
catch
{
flag = false;
}
return flag;
}
}
}
3、在web項(xiàng)目中應(yīng)用
只要在web.config的httpModules節(jié)點(diǎn)下面添加如下配置即可。
<httpModules>
<add name="SqlHttpModule" type="DotNet.Common.WebForm.SqlHttpModule, DotNet.Common.WebForm"></add>
</httpModules>
需要說(shuō)明的是,這個(gè)防止sql注入的方法在特定的小項(xiàng)目中還是很簡(jiǎn)潔高效的,但是不通用,通常我們都是選擇參數(shù)化(利用orm或者ado.net的參數(shù)化)方式防止sql注入。
附:asp.net在網(wǎng)頁(yè)頭部引入js腳本的簡(jiǎn)單方法
asp.net開(kāi)發(fā)少不了JavaScript的輔助。在通常項(xiàng)目中,js文件都組織在一個(gè)公共目錄如js文件夾下。隨著項(xiàng)目的深入,你會(huì)發(fā)現(xiàn)js腳本文件越來(lái)越多,公共的腳步庫(kù)越來(lái)越龐大。實(shí)際使用的時(shí)候,我們通常都是在頁(yè)面中通過(guò) <script src="..." type="text/javascript" >形式引入js文件,而且引入的越來(lái)越多。下面我們就來(lái)簡(jiǎn)單討論在每個(gè)頁(yè)面引入公共腳本庫(kù)的統(tǒng)一方式,而不用每個(gè)頁(yè)面都是很多<script src="..." type="text/javascript" >的形式。
和我們以前的做法一樣,定義一個(gè)頁(yè)面基類(lèi)叫BasePage,事件和方法如下:
Code
復(fù)制代碼 代碼如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Reflection;
using System.Text;
using System.IO;
namespace DotNet.Common.WebForm
{
using DotNet.Common.Model;
using DotNet.Common.Util;
public class BasePage : System.Web.UI.Page
{
public BasePage()
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
AddHeaderJs();//向網(wǎng)頁(yè)頭部添加js等文件
}
#region 網(wǎng)頁(yè)頭添加通用統(tǒng)一js文件
private void AddHeaderJs()
{
string jsPath = "~/js/";
string filePath = Server.MapPath(jsPath);
Literal lit = new Literal();
StringBuilder sb = new StringBuilder();
if (!Directory.Exists(filePath))
throw new Exception("路徑不存在");
List<string> listJs = new List<string>();
foreach (var item in Directory.GetFiles(filePath, "*.js", SearchOption.TopDirectoryOnly))
{
listJs.Add(Path.GetFileName(item));
}
foreach (var jsname in listJs)
{
sb.Append(ScriptInclude(jsPath + jsname));
}
lit.Text = sb.ToString();
Header.Controls.AddAt(1, lit);
}
private string ResolveHeaderUrl(string relativeUrl)
{
string url = null;
if (string.IsNullOrEmpty(relativeUrl))
{
url = string.Empty;
}
else if (!relativeUrl.StartsWith("~"))
{
url = relativeUrl;
}
else
{
var basePath = HttpContext.Current.Request.ApplicationPath;
url = basePath + relativeUrl.Substring(1);
url = url.Replace("http://", "/");
}
return url;
}
private string ScriptInclude(string url)
{
if (string.IsNullOrEmpty(url))
throw new Exception("路徑不存在");
string path = ResolveHeaderUrl(url);
return string.Format(@"<script src='{0}' type='text/javascript'></script>", path);
}
#endregion
}
}
這樣就簡(jiǎn)單地解決了引入公共js的問(wèn)題。同樣的原理,你也可以引入其他類(lèi)型的文件,如css等。
demo下載
相關(guān)文章
建立自定義的數(shù)據(jù)驅(qū)動(dòng)的本地化資源provider
本文探討了自定義的本地化資源提供者.如果想用一個(gè)可替代系統(tǒng)的資源處理方案,例如把所有的資源放入數(shù)據(jù)庫(kù)中,而不是放在分散的資源文件里,你可以自定義一個(gè)resource provider.2010-06-06.Net Compact Framework開(kāi)發(fā)小技巧 推薦
這篇文章對(duì)于.Net Compact Framework開(kāi)發(fā)的朋友有一定的幫助,內(nèi)容比較實(shí)用。2009-02-02Asp.net Core MVC中怎么把二級(jí)域名綁定到特定的控制器上
這篇文章主要介紹了Asp.net Core MVC中怎么把二級(jí)域名綁定到特定的控制器上,需要的朋友可以參考下2017-06-06Asp.Net Core使用SignalR進(jìn)行服務(wù)間調(diào)用方法示例
這篇文章主要介紹了Asp.Net Core使用SignalR進(jìn)行服務(wù)間調(diào)用方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12基于.NET BitmapImage 內(nèi)存釋放問(wèn)題的解決方法詳解
本篇文章是對(duì).NET BitmapImage 內(nèi)存釋放問(wèn)題的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05MVC 5 第一章 創(chuàng)建MVC 5 web應(yīng)用程序
本章將講述一些構(gòu)建ASP.NET MVC 5 web application的一些基礎(chǔ)知識(shí), 通過(guò)本章學(xué)習(xí),你應(yīng)該能夠掌握到構(gòu)建MVC 5應(yīng)用程序的基本步驟,并且通過(guò)展示一個(gè)完整的MVC 5 hello world應(yīng)用程序了解MVC 5應(yīng)用程序所帶來(lái)的用戶體驗(yàn)。2014-06-06在DataTable中執(zhí)行Select("條件")后,返回DataTable的方法
在DataTable中執(zhí)行Select("條件")后,返回DataTable的方法...2007-09-09