什么是sql注入
用一个最简单的例子说明,数据库中有一个表,user_table,
CREATE TABLE user_table(
id INTEGER PRIMARYKEY,
username VARCHAR(32),
password VARCHAR(41)
);
对一个用户进行认证,实际上就是将用户的输入即用户名和口令跟表中的各行进行比较,如果跟某行中的用户名和口令跟用户的输入完全匹配,那么该用户就会通过认证,并得到该行中的ID。假如用户提供的用户名和口令分别为lonelynerd15和mypassword,那么检查用户ID过程如下所示:
SELECT id FROM user_table WHERE username='lonelynerd15' AND password=PASSWORD('mypassword')
’OR 1=1--
口令;x
那么查询将会变成
SELECT id FROM user_table WHERE username=''OR 1=1--'AND password
=PASSWORD('x')
该双划符号--告诉SQL解析器,右边的东西全部是注释,所以不必理会。这样,查询字符串相当于:
SELECT id FROM user_table WHERE username='' OR 1=1
现在只要用户名为长度为零的字符串''或1=1这两个条件中一个为真,就返回用户标识符ID——我们知道,1=1是恒为真的。所以这个语句将返回user_table中的所有ID。在此种情况下,攻击者在username字段放入的是SQL指令'OR 1=1--而非数据。
通过上面的例子我们看到所谓的sql注入就是,构造SQL代码让服务器执行,获取敏感数据,或对数据进行破坏。主要的原因就是未对数据和命令进行严格的区分。
sql注入检测
经典的1=1、1=2测试法
比如:select * from Table where id=
我们自己构造ID值,ID值本来是1,我们在ID后面追加and 1=1,那么语句就变成了 select * from Table where id=1 and 1=1
因为id=1的网页是确实存在的,所以and拼接起来的语句前半句返回真,后半句1=1返回肯定也是真,整条语句查询结果为真,返回正常的页面。。。
但是如果提交and 1=2 前半句返回真,而我们自己构造的1=2肯定返回假,and逻辑与运算符 只有2边都为真才返回真,所以整条语句返回值为假,页面就会出错。
就能说明我们自己私自构造的语句可以被正常执行,那么证明可以进行sql注入
sql注入预防
防SQL注入的操作类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Data.OleDb;
namespace Web.view
{
/// <summary>
///SqlInject 的摘要说明
/// </summary>
public class SqlInject : System.Web.UI.Page
{
//检测到注入后的处理方式: 0:仅警告;1:警告+记录;2:警告+自定义错误页面;3:警告+记录+自定义错误页面
private const int _type = 0;
private const string errRedirectPage = "/err.aspx";
//如果记录注入信息,那么请设置:errMDBpath:数据库路径
private const string errMDBpath = "/SqlInject.mdb";
//过滤特征字符
//过滤特征字符
private static string StrKeyWord = ConfigurationManager.AppSettings["SqlKeyWord"]; //@"select|insert|delete|from|count(|drop table|update|truncate|asc(|mid(|char(|xp_cmdshell|exec|master|net local group administrators|net user|or|and";
private static string StrRegex = ConfigurationManager.AppSettings["SqlRegex"]; //@";|/|(|)|[|]|{|}|%|@|*|'|!"; // 原始过滤条件:【-|;|,|/|(|)|[|]|{|}|%|@|*|'|!】
private HttpRequest request;
public SqlInject(System.Web.HttpRequest _request)
{
this.request = _request;
}
///<summary>
///检测SQL注入及记录、显示出错信息
///</summary>
public void CheckSqlInject()
{
bool isInject = false;
if (CheckRequestQuery() || CheckRequestForm())
{
isInject = true;
}
else
{
return;
}
switch (_type)
{
case 0:
ShowErr();
break;
case 1:
ShowErr();
SaveToMdb();
break;
case 2:
ShowErr();
string temp;
System.Web.HttpContext.Current.Response.Write("<script>setTimeout(\"" + "location.href='" + errRedirectPage + "'" + "\",5000)</script>");
break;
case 3:
ShowErr();
SaveToMdb();
System.Web.HttpContext.Current.Response.Write("<script>setTimeout(\"" + "location.href='" + errRedirectPage + "'" + "\",5000)</script>");
break;
default:
break;
}
System.Web.HttpContext.Current.Response.End();
}
private void SaveToMdb()
{
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + Server.MapPath(errMDBpath));
conn.Open();
OleDbCommand cmd = conn.CreateCommand();
cmd.CommandText = "insert into [Record] (sIP,sDate,sPath) values ('" +
request.ServerVariables["REMOTE_ADDR"].ToString() + "','" +
DateTime.Now + "','" + request.ServerVariables["URL"].ToLower() + RelaceSingleQuotes(request.QueryString.ToString()) + "')";
int code = cmd.ExecuteNonQuery();
if (code == 1)
System.Web.HttpContext.Current.Response.Write("<br>****以上信息已记录至日志数据库****");
else
System.Web.HttpContext.Current.Response.Write("<br>日志数据库出错");
conn.Close();
}
private string RelaceSingleQuotes(string _url)
{
string URL = _url.Replace("'", "单引号");
return URL;
}
private void ShowErr()
{
//string msg = @"<font color=red>请不要尝试未授权之入侵检测!</font>" + @"<br><br>";
//msg += @"操作IP:" + request.ServerVariables["REMOTE_ADDR"] + @"<br>";
//msg += @"操作时间:" + DateTime.Now + @"<br>";
//msg += @"页面:" + request.ServerVariables["URL"].ToLower() + request.QueryString.ToString() + @"<br>";
//msg += @"<a href='#' οnclick='javascript:window.close()'>关闭</a>";
//System.Web.HttpContext.Current.Response.Clear();
//System.Web.HttpContext.Current.Response.Write(msg);
System.Web.HttpContext.Current.Response.Write("请不要尝试未授权之入侵检测!");
}
///<summary>
/// 特征字符
///</summary>
public static string KeyWord
{
get
{
return StrKeyWord;
}
}
///<summary>
/// 特征符号
///</summary>
public static string RegexString
{
get
{
return StrRegex;
}
}
///<summary>
///检查字符串中是否包含Sql注入关键字
/// <param name="_key">被检查的字符串</param>
/// <returns>如果包含注入true;否则返回false</returns>
///</summary>
private static bool CheckKeyWord(string _key)
{
string[] pattenString = StrKeyWord.Split('|');
string[] pattenRegex = StrRegex.Split('|');
foreach (string sqlParam in pattenString)
{
if (_key.Contains(sqlParam + " ") || _key.Contains(" " + sqlParam))
{
return true;
}
}
foreach (string sqlParam in pattenRegex)
{
if (_key.Contains(sqlParam))
{
return true;
}
}
return false;
}
///<summary>
///检查URL中是否包含Sql注入
/// <param name="_request">当前HttpRequest对象</param>
/// <returns>如果包含注入true;否则返回false</returns>
///</summary>
public bool CheckRequestQuery()
{
if (request.QueryString.Count > 0)
{
foreach (string sqlParam in this.request.QueryString)
{
if (sqlParam == "__VIEWSTATE") continue;
if (sqlParam == "__EVENTVALIDATION") continue;
if (CheckKeyWord(request.QueryString[sqlParam].ToLower()))
{
return true;
}
}
}
return false;
}
///<summary>
///检查提交的表单中是否包含Sql注入
/// <param name="_request">当前HttpRequest对象</param>
/// <returns>如果包含注入true;否则返回false</returns>
///</summary>
public bool CheckRequestForm()
{
if (request.Form.Count > 0)
{
foreach (string sqlParam in this.request.Form)
{
if (sqlParam == "__VIEWSTATE") continue;
if (sqlParam == "__EVENTVALIDATION") continue;
if (CheckKeyWord(request.Form[sqlParam]))
{
return true;
}
}
}
return false;
}
}
}
Web.Config中添加防SQL注入的特征字符集:
<!--防SQL注入时的特征字符集-->
<add key="SqlKeyWord" value="select|insert|delete|from|count(|drop table|update|truncate|asc(|mid(|char(|xp_cmdshell|exec|master|net local group administrators|net user|or|and"/>
<add key="SqlRegex" value=";|(|)|[|]|{|}|%|@|*|'|!"/>
在站点的Global文件中,添加 Application_BeginRequest 事件即可:
protected void Application_BeginRequest(object sender, EventArgs e)
{
//防SQL注入代码
SqlInject myCheck = new SqlInject(this.Request);
myCheck.CheckSqlInject();
}
以上的方法,是在网上找到的,经过了本人的亲自试验