并非人人是高手,并非人人是神仙,我也有不懂的地方,我也有不注意的技术问题,多交流多学习就是最好的提高方法
其实对与初学者来说,进行的动态的查询语句拼接也不是那么好做的事情,就是做出来了,也未必是经得起考验的足够灵活好用的,未必是能拿得出手可以进行推广的,是否能拿得出就是其中的关键。
今天检查公司的软件项目质量,发现有2个同事写的程序存在SQL注入攻击的漏洞,当然也不能怪罪人家,他们也是刚参加工作1-2年,还没有那么丰富的技术经验、安全意识,不会注意到自己编写的系统会有严重的安全漏洞。
公司在宁波也有一个政府网站的项目,在做系统安全检查自动扫描时,也被查出了一些SQL注入攻击的漏洞,这也使得让我更加提高了系统是否存在安全漏洞的意识,当然我写的系统很少会有这类的漏洞,但是整个公司有几十号人在做开发公司,所以也难免别人不会犯错。
人工检查是否有SQL注入安全漏洞,其实非常简单,只要在查询输入框里输入有单引号的字符“'”,例如查询条件输入“吉日'嘎拉”其中有单引号,很可能这个查询的页面就崩溃了出现了错误页面,或者跳转到出错页面了,若有这样的情况发生,几乎99.3721%都可以看做是有潜在的SQL注入攻击漏洞。
防止这个错误的发生,从技术上应该说是要用“参数化的查询”,贴一些代码,给大家参考一下我的做法:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
#region
public DataTable Search(string folderId, string searchValue, Boolean deleteMark) 查询
/// <summary>
/// 查询
/// </summary>
/// <param name="folderId"> 目录 </param>
/// <param name="searchValue"> 查询条件 </param>
/// <param name="deleteMark"> 删除标志 </param>
/// <returns> 数据表 </returns>
public DataTable Search( string folderId, string searchValue, Boolean deleteMark)
{
// 一、这里是将Boolean值转换为int类型。
int delete = deleteMark ? 1 : 0 ;
// 二、这里是开始进行动态SQL语句拼接,字段名、表明都进行了常量定义,表名字段名发生变化时,很容易就知道程序哪里都调用了这些。
string sqlQuery = string .Empty;
sqlQuery = " SELECT " + BaseNewsTable.FieldId
+ " , " + BaseNewsTable.FieldFolderId
+ " , " + BaseNewsTable.FieldTitle
+ " , " + BaseNewsTable.FieldFilePath
+ " , " + BaseNewsTable.FieldFileSize
+ " , " + BaseNewsTable.FieldReadCount
+ " , " + BaseNewsTable.FieldDescription
+ " , " + BaseNewsTable.FieldCategoryCode
+ " , " + BaseNewsTable.FieldEnabled
+ " , " + BaseNewsTable.FieldDeleteMark
+ " , " + BaseNewsTable.FieldSortCode
+ " , " + BaseNewsTable.FieldCreateUserId
+ " , " + BaseNewsTable.FieldCreateUserRealname
+ " , " + BaseNewsTable.FieldCreateDate
+ " , " + BaseNewsTable.FieldModifyUserId
+ " , " + BaseNewsTable.FieldModifyUserRealname
+ " , " + BaseNewsTable.FieldModifyDate
+ " FROM " + this .CurrentTableName
+ " WHERE " + BaseNewsTable.FieldDeleteMark + " = " + delete;
// 三、我们认为 folderId 这个查询条件是安全,不是人为输入的参数,所以直接进行了SQL语句拼接
if ( ! String.IsNullOrEmpty(folderId))
{
sqlQuery += " AND " + BaseNewsTable.FieldFolderId + " = ' " + folderId + " ' " ;
}
// 四、这里是进行参数化的准备,因为是多个不确定的查询参数,所以用了List。
List < DbParameter > dbParameters = new List < DbParameter > ();
// 五、这里看查询条件是否为空
searchValue = searchValue.Trim();
if ( ! String.IsNullOrEmpty(searchValue))
{
// 六、这里是进行支持多种数据库的参数化查询
sqlQuery += " AND ( " + BaseNewsTable.FieldTitle + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldTitle);
sqlQuery += " OR " + BaseNewsTable.FieldCreateUserRealname + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldCreateUserRealname);
sqlQuery += " OR " + BaseNewsTable.FieldContents + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldContents);
sqlQuery += " OR " + BaseNewsTable.FieldDescription + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldDescription) + " ) " ;
// 七、这里是判断,用户是否已经输入了%
if (searchValue.IndexOf( " % " ) < 0 )
{
searchValue = " % " + searchValue + " % " ;
}
// 八、这里生成支持多数据库的参数
dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FieldTitle, searchValue));
dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FieldCreateUserRealname, searchValue));
%3
/// <summary>
/// 查询
/// </summary>
/// <param name="folderId"> 目录 </param>
/// <param name="searchValue"> 查询条件 </param>
/// <param name="deleteMark"> 删除标志 </param>
/// <returns> 数据表 </returns>
public DataTable Search( string folderId, string searchValue, Boolean deleteMark)
{
// 一、这里是将Boolean值转换为int类型。
int delete = deleteMark ? 1 : 0 ;
// 二、这里是开始进行动态SQL语句拼接,字段名、表明都进行了常量定义,表名字段名发生变化时,很容易就知道程序哪里都调用了这些。
string sqlQuery = string .Empty;
sqlQuery = " SELECT " + BaseNewsTable.FieldId
+ " , " + BaseNewsTable.FieldFolderId
+ " , " + BaseNewsTable.FieldTitle
+ " , " + BaseNewsTable.FieldFilePath
+ " , " + BaseNewsTable.FieldFileSize
+ " , " + BaseNewsTable.FieldReadCount
+ " , " + BaseNewsTable.FieldDescription
+ " , " + BaseNewsTable.FieldCategoryCode
+ " , " + BaseNewsTable.FieldEnabled
+ " , " + BaseNewsTable.FieldDeleteMark
+ " , " + BaseNewsTable.FieldSortCode
+ " , " + BaseNewsTable.FieldCreateUserId
+ " , " + BaseNewsTable.FieldCreateUserRealname
+ " , " + BaseNewsTable.FieldCreateDate
+ " , " + BaseNewsTable.FieldModifyUserId
+ " , " + BaseNewsTable.FieldModifyUserRealname
+ " , " + BaseNewsTable.FieldModifyDate
+ " FROM " + this .CurrentTableName
+ " WHERE " + BaseNewsTable.FieldDeleteMark + " = " + delete;
// 三、我们认为 folderId 这个查询条件是安全,不是人为输入的参数,所以直接进行了SQL语句拼接
if ( ! String.IsNullOrEmpty(folderId))
{
sqlQuery += " AND " + BaseNewsTable.FieldFolderId + " = ' " + folderId + " ' " ;
}
// 四、这里是进行参数化的准备,因为是多个不确定的查询参数,所以用了List。
List < DbParameter > dbParameters = new List < DbParameter > ();
// 五、这里看查询条件是否为空
searchValue = searchValue.Trim();
if ( ! String.IsNullOrEmpty(searchValue))
{
// 六、这里是进行支持多种数据库的参数化查询
sqlQuery += " AND ( " + BaseNewsTable.FieldTitle + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldTitle);
sqlQuery += " OR " + BaseNewsTable.FieldCreateUserRealname + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldCreateUserRealname);
sqlQuery += " OR " + BaseNewsTable.FieldContents + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldContents);
sqlQuery += " OR " + BaseNewsTable.FieldDescription + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FieldDescription) + " ) " ;
// 七、这里是判断,用户是否已经输入了%
if (searchValue.IndexOf( " % " ) < 0 )
{
searchValue = " % " + searchValue + " % " ;
}
// 八、这里生成支持多数据库的参数
dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FieldTitle, searchValue));
dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FieldCreateUserRealname, searchValue));
%3