SQL 中单引号 和一些特殊字符的处理
为了防止程序SQL语句错误以及SQL注入,单引号必须经过处理。有2种办法:
1、使用参数,比如SELECT * FROM yourTable WHERE name = @name;
在Java中就是用预处理PreparedStatement来添加参数。
2、如果不用参数,而用字符串拼接的话,单引号必须经过判断并替换,在数据库中,用2个单引号代表1个实际的单引号。所以,如果是拼接方式,需要用String.Replace("’", "”")来替换一下,将1个单引号替换为2个就没有问题了。
一. SQL Injection及其防范的基本知识
可能大家都知道,SQL注入主要是利用字符型参数输入的检查漏洞。
比如说,程序中有这样的查询:
string sql = "SELECT * FROM SiteUsers WHERE UserName=" + userName + "";
其中的userName参数是从用户界面上输入的。
如果是正常的输入,比如"Peter",SQL语句会串接成:
"SELECT * FROM SiteUsers WHERE UserName=Peter";
如果攻击者输入的是下面的字符串:
"xxx; DROP TABLE SiteUsers WHERE 1=1 or UserName=xxx"
此时SQL语句会变成下面这个样子:
"SELECT * FROM SiteUsers WHERE UserName=xxx; DROP TABLE SiteUsers WHERE 1=1 or UserName=xxx";
其结果,得到执行的是两个SQL语句,第二个语句的后果就比较严重了。
防止注入的方法其实很简单,只要把用户输入的单引号变成双份就行了:
string sql = "SELECT * FROM SiteUsers WHERE UserName=" + userName.Replace("","") + "";
这样,如果输入的是上面那种恶意参数,整个SQL语句会变成:
"SELECT * FROM SiteUsers WHERE UserName=xxx; DROP TABLE SiteUsers WHERE 1=1 or UserName=xxx";
被执行的还是一个SQL语句,整个粗体部分都成为参数值。
一般的做法,是在程序中统一调用下面这样的共通函数,对参数进行处理:
private string SafeSqlLiteral(string inputSQL)
{
return inputSQL.Replace("", "");
}
由于很多人会疏忽这种单引号替换,所以真正安全的做法是使用参数化查询。
二. 参数化查询
在ADO.NET中,提供了一种参数化查询方法,可以替代上面这种拼接SQL语句的做法。
参数化查询的具体实现是:
(1)组织一个夹带参数名的SQL语句,作为SqlCommand的CommandText。
(2)使用Parameters.Add方法设置参数值。
(3)执行SqlCommand。(这个步骤跟上面那种拼接SQL的办法是一样的。)
下面是一个例子:
string sql = "SELECT T2.dep_code, T2.dep_name FROM DEP ";
sql += " WHERE T2.dep_name like (%+ @Param + %) ";
SqlCommand sqlCommand = new SqlCommand(sql,cn);
sqlCommand.Parameters.Add(new SqlParameter("Param", s));
其中的@Param就是参数名,s则是用户输入的查询条件字串。
(顺便注:Oracle查询语句参数用问号表示,不是"@参数名"的形式。)
使用这种参数化查询的办法,防止SQL注入的任务就交给ADO.Net了。
如果在项目中统一规定必须使用参数化查询,就不用担心因个别程序员的疏忽导致的SQL注入漏洞了。
但是,问题还没有完,SQL注入的漏洞是堵住了,但是查询结果的正确性,参数化查询并不能帮上什么忙。
三. 通配符问题
如果使用LIKE语句进行模糊查询,会有一些特殊的通配符问题。
SQL Server的通配符包括下划线(_)和百分号(%),分别表示单个字符和任意多字符。
如果用户输入参数中包括这些通配符,就会出现结果不正确的问题。
比如说:
WHERE T2.name like (%+ @Param + %)
如果用户输入下划线,他期待的结果应该是name字段值含有下划线的记录,但是结果是所有记录都会被查询出来。输入百分号也是如此。
为此,在将用户输入的内容作为参数值传入之前,必须进行通配符的转义处理(英文叫做Escape),也就是说,如果用户输入的查询条件中含有通配符,必须将这些字符作为数据而不是通配符来对待。
在SQL Server的查询语句中,将通配符转义为普通数据的方法是用方括号括起来。
比如说,如果想要查询带有下划线的字段,正确的写法是:
WHERE T2.name like (%+ [_] + %)
同样,如果想要查询带有百分号的字段,正确的写法是:
WHERE T2.name like (%+ [%] + %)
所以,即使使用参数化查询,也必须在将用户输入的内容当作参数值传入SqlCommand.Parameters之前,先进行下面的处理:
s = s.Replace("%", "[%]");
s = s.Replace("_", "[_]");
四. 方括号问题
如果你足够细心,可能发现了还有一个方括号问题。
既然方括号是用来界定数据内容的,那么如果用户输入的查询参数本身就包括方括号时,会出现什么结果呢?
根据用户的期望,如果输入一个方括号,查询结果中应该只包括那些字段值中含有方括号的记录。
但是实验结果表明,如果是没有配成对的单个左方括号,查询时这个左方括号会被忽略。
也就是说,下面这个语句:
WHERE T2.name like (%+ [ + %)
等价于下面这个语句:
WHERE T2.name like (%+ + %)
这将导致查询结果中包含表中的全部记录,就像没有任何过滤条件一样。
为此,如果用户输入的查询条件中含有左方括号的话,还必须对左方括号进行转义:
s = s.Replace("[", "[[]");
注:右方括号没有这个问题。
五. 其他注意事项
按照微软的建议,凡是有可能导致问题的输入,可以在UI部分就进行检查并拒掉。
这些可疑输入包括:
分号(;):多个查询语句之间的分隔符,注入攻击时的恶意查询语句往往就是第二个查询语句。
单引号():字符串数据分隔符,这是最危险的,前面已经讨论了。
注释符(–或者/*,*/):有些数据库可以利用注释设置一些查询引擎的行为,比如如何利用索引等。
xp_:扩展存储过程的前缀,SQL注入攻击得手之后,攻击者往往会通过执行xp_cmdshell之类的扩展存储过程,获取系统信息,甚至控制、破坏系统。
六、结论
为了防止SQL注入,同时避免用户输入特殊字符时查询结果不准确的问题,应该做两件事:
(1)使用参数化查询。
(2)在使用用户输入的字符串数据设置查询参数值之前,首先调用下面的共通处理函数:
private static string ConvertSql(string sql)
{
//sql = sql.Replace("", ""); // ADO.NET已经做了,不要自己做
sql = sql.Replace("[", "[[]"); // 这句话一定要在下面两个语句之前,否则作为转义符的方括号会被当作数据被再次处理
sql = sql.Replace("_", "[_]");
sql = sql.Replace("%", "[%]");
return sql;
}
SQL 中单引号 和一些特殊字符的处理的更多相关文章
- sql 中单引号内嵌套单引号该怎么解决
# 在mybatis 中写过一个比较少见的sql, 单引号呢需要嵌套一个单引号,使用双引号就会报错,怎么解决呢: * 这个时候可以使用两个单引号,eg : select id from pgr_dij ...
- SQL中单引号和双引号
比如说: String sql = "select * from clients where logname='" + name + "'and password='&q ...
- SQL对like 操作中的特殊字符处理方法
SQL对like 操作中的特殊字符处理方法: SQL Server查询过程中,单引号 ' 是特殊字符,所以在查询的时候要转换成双单引号 '' . 在like操作还有以下特殊字符:下划线_, ...
- PHP中单引号、双引号和转义字符
在PHP语言总,单引号与双引号的作用不尽相同. PHP单引号及双引号均可以修饰字符串类型的数据,如果修饰的字符串中含有变量(例$name):最大的区别是:双引号会替换变量的值,而单引号会把它当做字符串 ...
- PHP中单引号与双引号的区别分析
From: http://www.jb51.net/article/53973.htm 在PHP中,我们可以使用单引号或者双引号来表示字符串.不过我们作为开发者,应该了解其中的区别.单引号与双引号对于 ...
- Linux Shell中单引号、双引号、反引号的区别【转载】
linux shell可以识别4种不同类型的引字符号: 单引号字符' 双引号字符" 反斜杠字符\ 反引号字符` 1. 单引号 ( '' )# grep Susan phonebook Sus ...
- Shell脚本中单引号(‘)和双引号(“)的使用区别[转载]
shell可以识别4种不同类型的引字符号: 单引号字符' 双引号字符" 反斜杠字符\ 反引号字符` 1. 单引号 ( '' ) # grep Susan phonebook Susan Go ...
- C中单引号中放多个字符
在C中时常有类似这样的写法: #define EVENT_MAGIC 'evnt' int magic = EVENT_MAGIC; 乍一看来,这样的方式有点不理解.听网友说: C中单引号内最多存4个 ...
- linux shell中单引号、双引号、反引号、反斜杠的区别
摘自http://www.jb51.net/article/33495.htm 1. 单引号 ( '' ) # grep Susan phonebook Susan Goldberg 403-212- ...
随机推荐
- php 加密压缩
php 把文件打成压缩包 ,可以去搜下 pclzip 搜很好多地方没有找到对压缩包进行加密操作的. 如果服务器是linux 那么见代码: $filename="test.csv"; ...
- Python 安装出错:Setup script exited with error: command 'gcc' failed with exit status 1
退出当前环境: logout (再重新登录进去) yum install python-devel -yyum install libevent-devel -y 把环境更新下yum instal ...
- [转]Shell脚本之无限循环的两种方法
方法一: while循环,用的比较多的 #!/bin/bash set j= while true do let "j=j+1" echo "----------j is ...
- Java虚拟机七 虚拟机监控
jstack 用于导出Java应用程序的线程堆栈:jstack [-l] <pid> -l 选项用于打印锁的附加信息 jstack -l 2348 > /data/deadlock. ...
- windows 环境下node开发环境搭配问题
当我们使用ccap 生成验证码时,需要node-gyp构建build,但是c的编译环境是在python,vc. node-gyp包 https://github.com/TooTallNate/nod ...
- 利用 :first-child 和 :nth-last-child 确定子元素数目
读<css揭秘>时,发现选择器的神奇作用,可以确定子元素数目,比如: li:first-child:nth-last-child(2),li:first-child:nth-last-ch ...
- Navicat 同步数据库中数据
Navicat工具同步两个数据库中的数据 第一步在我们的电脑里面打开navicat软件,打开要复制表的数据库,如下图所示: 第二步点击上方的“工具->数据传输”,如下图所示: 第三步进 ...
- ubuntu16.04下笔记本电脑扩展双屏安装过程
想给笔记本电脑外界一个显示屏,因为科研需要,我的笔记本是windows10加Ubuntu16.04双系统,主要使用Ubuntu系统. 首先是硬件 一个外置显示屏是必须的了,然后我的笔电上只有HDMI接 ...
- Docker Hub Mirror
什么是Docker Hub Mirror? 根据Docker的官方文档,Mirror的定义是: Such a registry is provided by a third-party hosting ...
- vue - 组件的创建
组件的创建 vue的核心基础就是组件的使用,玩好了组件才能将前面学的基础更好的运用起来.组件的使用更使我们的项目解耦合.更加符合vue的设计思想MVVM. 那接下来就跟我看一下如何在一个Vue实例中使 ...