sql注入简单简单讲解
在这贴上一个详细讲解SQL注入的文章链接 ,https://blog.youkuaiyun.com/u011280083/article/details/79116615
(一)了解注入原理
为什么会存在sql注入呢,只能说SQL出身不好。因为sql作为一种解释型语言,在运行时是由一个运行时组件解释语言代码并执行其中包含的指令的语言。基于这种执行方式,产生了一系列叫做代码注入(code injection)的漏洞 。它的数据其实是由程序员编写的代码和用户提交的数据共同组成的。程序员在web开发时,没有过滤敏感字符,绑定变量,导致攻击者可以通过sql灵活多变的语法,构造精心巧妙的语句,不择手段,达成目的,或者通过系统报错,返回对自己有用的信息。
我们在学JDBC和SQL时,讲师跟我们说 Statement不能防止SQL注入, PreparedStatement能够防止SQL注入. 没错, 这句话是没有问题的, 但到底如何进行SQL注入?怎么直观的去了解SQL注入?这还是需要花一定的时间去实验的.预编译语句java.sql.PreparedStatement ,扩展自 Statement,不但具有 Statement 的所有能力而且具有更强大的功能。不同的是,PreparedStatement 是在创建语句对象的同时给出要执行的sql语句。这样,sql语句就会被系统进行预编译,执行的速度会有所增加,尤其是在执行大语句的时候,效果更加理想。而且PreparedStatement中绑定的sql语句是可以带参数的。
(二)架设注入环境
我们知道现在php作为一门网页编程语言真是风生水起,利用lamp(linux+apache+mysql+php)或者wamp(windows+apache+mysql+php)搭建网站环境,如腾讯的discuz、阿里的 phpwind 以及织梦的dedecms 等建站程序,占据了国内网站的半壁江山。那么我们今天即以这种架构为假象敌,首先是在本地架设wamp环境。需要用到的工具有:apache,mysql,php ,这几个组件可以单独下载安装,不过安装配置过程较为繁琐,还是建议新手直接从网上下载phpnow ,一个绿色程序,包含上述三个组件,傻瓜化操作就可以了。
(三)简单讲解注入手法
一般网站的登陆如果像下面这种登陆验证的sql语句的话:
select * from `表名`where username='admin' and password=md5('123123')
如果用户名和密码都输入正确,肯定能够成功登陆。但是,如果我们输入一个错误的用户名或密码呢?很明显,肯定登入不了吧。恩,正常情况下是如此,但是对于有SQL注入漏洞的网站来说,只要构造个特殊的“字符串”,照样能够成功登录。
比如:在用户名输入框中输入:’or 1=1#,密码随便输入,这时候的合成后的SQL查询语句为:
select * from `表名` where username='' or 1=1#' and password=md5('')
语义分析:“#”在mysql中是注释符,这样井号后面的内容将被mysql视为注释内容,这样就不会去执行了,换句话说,以下的两句sql语句等价:
select * from users where username='' or 1=1#' and password=md5('')
等价于
select * from users where username='' or 1=1
因为1=1永远都是成立的,即where子句总是为真,将该sql进一步简化之后,等价如下select语句:
select * from `表名`
没错,该sql语句的作用是检索表中的所有字段
PDO防止SQL注入详细介绍
使用PDO访问MySQL数据库时,真正的real prepared statements 默认情况下是不使用的。为了解决这个问题,你必须禁用 prepared statements的仿真效果。下面是使用PDO创建链接的例子:
复制代码 代码如下:
- $dbh = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
- $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setAttribute()这一行是强制性的,它会告诉 PDO 禁用模拟预处理语句,并使用 real parepared statements 。这可以确保SQL语句和相应的值在传递到mysql服务器之前是不会被PHP解析的(禁止了所有可能的恶意SQL注入攻击)。虽然你可以配置文件中设置字符集的属性(charset=utf8),但是需要格外注意的是,老版本的 PHP( < 5.3.6)在DSN中是忽略字符参数的。
我们来看一段完整的代码使用实例:
复制代码 代码如下:
- $dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");
- $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的仿真效果
- $dbh->exec("set names 'utf8'");
- $sql="select * from test where name = ? and password = ?";
- $stmt = $dbh->prepare($sql);
- $exeres = $stmt->execute(array($testname, $pass));
- if ($exeres) {
- while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
- print_r($row);
- }
- }
- $dbh = null;
上面这段代码就可以防范简单的sql注入。为什么呢?
当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会。
但是我们需要注意的是以下几种情况,PDO并不能帮助你防范SQL注入
1、你不能让占位符 ? 代替一组值,如:
复制代码 代码如下:
SELECT * FROM blog WHERE userid IN ( ? );
2、你不能让占位符代替数据表名或列名,如:
复制代码 代码如下:
SELECT * FROM blog ORDER BY ?;
3、你不能让占位符 ? 代替任何其他SQL语法,如:
复制代码 代码如下:
SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog;
其实现在的许多网站都对sql注入做了或多或少的处理,很少有可以使用这种手段攻击网站的机会。但总会有一些遗漏的网站还等着你去发现,如果对sql注入感兴趣的可以去看开篇时链接文章或自行搜索,网上好多。但一定要记住学会了可不要干坏事,保持初心。