看到有人说了判断能否sql注入的方法:

  1. 简单的在参数后边加一个单引号,就可以快速判断是否可以进行SQL注入,这个百试百灵,如果有漏洞的话,一般会报错。

下面内容参考了这两篇文章

  1. http://blog.csdn.net/stilling2006/article/details/8526458
  2.  
  3. http://www.aichengxu.com/view/43982

nginx配置文件位置:/usr/local/etc/nginx/nginx.conf

主目录位置:/usr/local/Cellar/nginx/1.10.1/

Symfony位置:/Users/baidu/Documents/Data/Work/Installed/symfony/mywebsite/web

先在主目录创建一个文件 test.php,内容如下:

  1. <?php
  2. echo "PHP version:" . PHP_VERSION . "<br/>";
  3.  
  4. $con = mysql_connect('10.117.146.21:8306', 'root', '[password]');
  5. mysql_select_db('springdemo', $con);
  6. $sql = 'select nickname from user where id = 1';
  7. $result = mysql_query($sql);
  8.  
  9. print_r('rows:' . mysql_num_rows($result) . '<br/>');
  10. while ($row = mysql_fetch_array($result)) {
  11. print_r($row['nickname'] . '<br/>');
  12. }
  13.  
  14. mysql_close($con);
  15. ?>

上面,注意几个细节:

1. mysql连接要关的,使用mysql_close,之前因为没关,始终有连接存在

2. mysql_num_rows获得行数,mysql_fetch_array获得每次结果。

然后,nginx运行之后,得到运行结果:

  1. http://localhost:8080/test.php
  2.  
  3. PHP version:5.5.30
  4. rows:1
  5. abc

下面,改造成从参数拿sql参数。

  1. <?php
  2. echo "PHP version:" . PHP_VERSION . "<br/>";
  3.  
  4. $con = mysql_connect('10.117.146.21:8306', 'root', '[password]');
  5. mysql_select_db('springdemo', $con);
  6.  
  7. $input_id = trim($_GET['id']);
  8. $sql = 'select nickname from user where id = ' . $input_id;
  9. var_dump('SQL is:' . $sql);
  10. $result = mysql_query($sql);
  11.  
  12. if ($result != null) {
  13. print_r('rows:' . mysql_num_rows($result) . '<br/>');
  14. while ($row = mysql_fetch_array($result)) {
  15. print_r($row['nickname'] . '<br/>');
  16. }
  17. }
  18.  
  19. mysql_close($con);
  20. ?>

在上面,会使用id参数添加到sql里面,并且会将sql打印出来。

得到结果

  1. http://localhost:8080/test.php?id=3
  2.  
  3. PHP version:5.5.30
  4. string(50) "SQL is:select nickname from user where id = 3
  5. " rows:1
  6. micro
  7.  
  8. http://localhost:8080/test.php?id=3 or 1=1
  9.  
  10. PHP version:5.5.30
  11. string(57) "SQL is:select nickname from user where id = 3 or 1=1
  12. " rows:4
  13. abc
  14. micro
  15. helloworld
  16. 你好
  17.  
  18. 注意,开始的时候上面输出'你好'的是中文乱码。只需要在php文件开始加上下面这句,就可以避免乱码:
  19.  
  20. <?php
  21. header('Content-Type: text/html; charset=utf-8');

从上面可以看出,发生了sql注入。用户可以打印出所有的用户信息。

再引申一下。有的时候,我们会用引号将参数包住,但是这样仍然不能解决问题。

将PHP改成如下:

  1. <?php
  2. header('Content-Type: text/html; charset=utf-8');
  3. echo "PHP version:" . PHP_VERSION . "<br/>";
  4.  
  5. $con = mysql_connect('10.117.146.21:8306', 'root', '[password]');
  6. mysql_select_db('springdemo', $con);
  7.  
  8. $input_id = trim($_GET['id']);
  9. $sql = 'select nickname from user where id = \'' . $input_id . '\'';
  10. print_r('SQL is:' . $sql . '<br/>');
  11. $result = mysql_query($sql);
  12.  
  13. if ($result != null) {
  14. print_r('rows:' . mysql_num_rows($result) . '<br/>');
  15. while ($row = mysql_fetch_array($result)) {
  16. print_r($row['nickname'] . '<br/>');
  17. }
  18. }
  19.  
  20. mysql_close($con);
  21. ?>

上面把var_dump换成了print_r,以免sql语句总是换行。

这时候,不同url访问获得的结果如下:

  1. http://localhost:8080/test.php?id=3
  2.  
  3. PHP version:5.5.30
  4. SQL is:select nickname from user where id = '3'
  5. rows:1
  6. micro
  7.  
  8. http://localhost:8080/test.php?id=3 or 1=1
  9.  
  10. PHP version:5.5.30
  11. SQL is:select nickname from user where id = '3 or 1=1'
  12. rows:1
  13. micro
  14.  
  15. http://localhost:8080/test.php?id=3' or '1'='1
  16.  
  17. PHP version:5.5.30
  18. SQL is:select nickname from user where id = '3' or '1'='1'
  19. rows:4
  20. abc
  21. micro
  22. helloworld
  23. 你好

上面可以看到,加了引号,对于之前的情况是能够避免了。但是只要稍作调整,又能够成功进行sql注入了。

有时候,攻击者还会在参数里面加上'--'。这是因为sql会认为 -- 右边的都是注释,这样能够更方便对sql的控制。

首先将test.php改成如下,增加一个参数:

  1. <?php
  2. header('Content-Type: text/html; charset=utf-8');
  3. echo "PHP version:" . PHP_VERSION . "<br/>";
  4.  
  5. $con = mysql_connect('10.117.146.21:8306', 'root', '[password]');
  6. mysql_select_db('springdemo', $con);
  7.  
  8. $input_id = trim($_GET['id']);
  9. $name = trim($_GET['name']);
  10. $sql = 'select nickname from user where id = \'' . $input_id . '\' and nickname = \'' . $name . '\'';
  11. print_r('SQL is:' . $sql . '<br/>');
  12. $result = mysql_query($sql);
  13.  
  14. if ($result != null) {
  15. print_r('rows:' . mysql_num_rows($result) . '<br/>');
  16. while ($row = mysql_fetch_array($result)) {
  17. print_r($row['nickname'] . '<br/>');
  18. }
  19. }
  20.  
  21. mysql_close($con);
  22. ?>

然后对于不同url的访问结果:

  1. http://localhost:8080/test.php?id=3
  2.  
  3. PHP version:5.5.30
  4. SQL is:select nickname from user where id = '3' and nickname = ''
  5. rows:0
  6.  
  7. http://localhost:8080/test.php?id=3&name=micro
  8.  
  9. PHP version:5.5.30
  10. SQL is:select nickname from user where id = '3' and nickname = 'micro'
  11. rows:1
  12. micro
  13.  
  14. http://localhost:8080/test.php?id=3 or 1=1
  15.  
  16. PHP version:5.5.30
  17. SQL is:select nickname from user where id = '3 or 1=1' and nickname = ''
  18. rows:0
  19.  
  20. http://localhost:8080/test.php?id=3' or '1'='1
  21.  
  22. PHP version:5.5.30
  23. SQL is:select nickname from user where id = '3' or '1'='1' and nickname = ''
  24. rows:1
  25. micro
  1. http://localhost:8080/test.php?id=3' or '1'='1&name=micro
  2.  
  3. PHP version:5.5.30
    SQL is:select nickname from user where id = '3' or '1'='1' and nickname = 'micro'
    rows:1
    micro

以上例子可以看出,即使加了sql注入,但是拼出来的sql仍然受到了限制只能返回一行。不过,加了 -- 注释符号,情况就又不一样了。

  1. http://localhost:8080/test.php?id=3' or 1=1 --'
  2.  
  3. PHP version:5.5.30
  4. SQL is:select nickname from user where id = '3' or 1=1 --'' and nickname = ''
  5. rows:1
  6. micro
  7.  
  8. http://localhost:8080/test.php?id=3' or 1=1 -- '
  9.  
  10. PHP version:5.5.30
  11. SQL is:select nickname from user where id = '3' or 1=1 -- '' and nickname = ''
  12. rows:4
  13. chaoliu
  14. micro
  15. helloworld
  16. 你好
  17.  
  18. http://localhost:8080/test.php?id=3' or 1=1; -- '
  19.  
  20. PHP version:5.5.30
  21. SQL is:select nickname from user where id = '3' or 1=1; -- '' and nickname = ''
  22. rows:4
  23. chaoliu
  24. micro
  25. helloworld
  26. 你好

这3个例子要仔细看。一定要注意,-- 的前后都要加上空格才会生效。

另外,在参数里加上分号; 对于拼接sql的代码,也是会生效的。

现在试试,直接在url里面对数据库内容进行修改。

  1. http://localhost:8080/test.php?id=3'; update user set nickname='a' where id=1; -- '
  2.  
  3. PHP version:5.5.30
  4. SQL is:select nickname from user where id = '3'; update user set nickname='a' where id=1; -- '' and nickname = ''
  5.  
  6. 貌似运行没有成功。
  7. 但是直接把sql贴到Mysql客户端运行是可以成功的。

PHP的error log是在

/usr/local/var/log/php_errors.log

但是没有看到有打印错误内容。

去查看了Mysql的error日志,在Mysql机器上面的

/home/work/.jumbo/var/lib/mysql 目录里面有几种日志,也没有看到信息。

所以想到查binlog看看。binlog的查看方法(在Mysql客户端里面):

  1. mysql> show binlog events in 'mysql-bin.000005'\G
  2.  
  3. *************************** 207. row ***************************
  4. Log_name: mysql-bin.000005
  5. Pos: 18070
  6. Event_type: Query
  7. Server_id: 1
  8. End_log_pos: 18144
  9. Info: BEGIN
  10. *************************** 208. row ***************************
  11. Log_name: mysql-bin.000005
  12. Pos: 18144
  13. Event_type: Query
  14. Server_id: 1
  15. End_log_pos: 18254
  16. Info: use `springdemo`; update user set nickname='abc' where id=1
  17. *************************** 209. row ***************************
  18. Log_name: mysql-bin.000005
  19. Pos: 18254
  20. Event_type: Xid
  21. Server_id: 1
  22. End_log_pos: 18281
  23. Info: COMMIT /* xid=7772 */
  24. 209 rows in set (0.00 sec)

里面只记录了更新的日志。而且发现通过上面修改的更新是没有的。

还有一些其他binlog相关的命令:

  1. mysql> show master status\G
  2. *************************** 1. row ***************************
  3. File: mysql-bin.000005
  4. Position: 18281
  5. Binlog_Do_DB:
  6. Binlog_Ignore_DB:
  7. 1 row in set (0.00 sec)
  8.  
  9. mysql> show binary logs;
  10. +------------------+-----------+
  11. | Log_name | File_size |
  12. +------------------+-----------+
  13. | mysql-bin.000001 | 29776 |
  14. | mysql-bin.000002 | 1036239 |
  15. | mysql-bin.000003 | 769 |
  16. | mysql-bin.000004 | 397 |
  17. | mysql-bin.000005 | 18281 |
  18. +------------------+-----------+
  19. 5 rows in set (0.00 sec)
  20.  
  21. 另外,也可以用mysqlbinlog工具查看。还没有试过。

看起来这条url是不能生效的。

  1. http://localhost:8080/test.php?id=3%27;%20update%20user%20set%20nickname=%27ab%27%20where%20id=1;%20--%20%27

又试了下drop table的命令

  1. http://localhost:8080/test.php?id=3%27;%20drop%20table%20users;%20--%20%27
  2.  
  3. 对于下面这个表:
  4. mysql> create table users ( a varchar(20), b varchar(10), primary key (a) );
  5. Query OK, 0 rows affected (0.12 sec)
  6.  
  7. 运行上面的url之后,仍然存在
    PHP version:5.5.30
    SQL is:select nickname from user where id = '3'; drop table users; -- '' and nickname = ''

与原文描述的不一样了:http://blog.sina.com.cn/s/blog_6a384fce0100n95f.html

下面来说解决的办法:

1. 通过正则表达式匹配校验,或其他格式的校验(较复杂不规范)

2. 通过addslashes或者str_replace(比如把引号'替换成\引号')处理(有漏洞)

3. 通过mysql_real_escape_string处理(有漏洞)

4. 通过mysqli处理,用PreparedStatement(推荐)

5. 通过PDO(PHP Data Object)处理,也是用PreparedStatement(推荐)

对于1,太复杂琐碎,不做讨论。

对于2其中的str_replace,也不规范,不做讨论。

2其中的addslashes和mysql_real_escape_string 都存在由于客户端和Mysql服务器编码方式不一致导致的编码转换丢失和字符一分为二导致的漏洞。后面详述,先看本来的方案。

参考 http://www.aichengxu.com/view/43982

addslashes:

  1. <?php
  2. header('Content-Type: text/html; charset=utf-8');
  3. echo "PHP version:" . PHP_VERSION . "<br/>";
  4.  
  5. $con = mysql_connect('10.117.146.21:8306', 'root', '[password]');
  6. mysql_select_db('springdemo', $con);
  7.  
  8. $input_id = addslashes($_GET['id']);
  9. $name = addslashes($_GET['name']);
  10. $sql = 'select nickname from user where id = \'' . $input_id . '\' and nickname = \'' . $name . '\'';
  11. print_r('SQL is:' . $sql . '<br/>');
  12. $result = mysql_query($sql);
  13.  
  14. if ($result != null) {
  15. print_r('rows:' . mysql_num_rows($result) . '<br/>');
  16. while ($row = mysql_fetch_array($result)) {
  17. print_r($row['nickname'] . '<br/>');
  18. }
  19. }
  20.  
  21. mysql_close($con);
  22. ?>

测试上面的一些URL:

  1. http://localhost:8080/test.php?id=3&name=micro
    PHP version:5.5.30
    SQL is:select nickname from user where id = '3' and nickname = 'micro'
    rows:1
    micro
    注:正常
  2.  
  3. http://localhost:8080/test.php?id=3%27%20or%201=1;%20--%20%27
  4.  
  5. PHP version:5.5.30
  6. SQL is:select nickname from user where id = '3\' or 1=1; -- \'' and nickname = ''
  7. rows:0
    注:防御成功

mysql_real_escape_string:

  1. <?php
  2. header('Content-Type: text/html; charset=utf-8');
  3. echo "PHP version:" . PHP_VERSION . "<br/>";
  4.  
  5. $con = mysql_connect('10.117.146.21:8306', 'root', '[password]');
  6. mysql_select_db('springdemo', $con);
  7.  
  8. $input_id = mysql_real_escape_string($_GET['id']);
  9. $name = mysql_real_escape_string($_GET['name']);
  10. $sql = 'select nickname from user where id = \'' . $input_id . '\' and nickname = \'' . $name . '\'';
  11. print_r('SQL is:' . $sql . '<br/>');
  12. $result = mysql_query($sql);
  13.  
  14. if ($result != null) {
  15. print_r('rows:' . mysql_num_rows($result) . '<br/>');
  16. while ($row = mysql_fetch_array($result)) {
  17. print_r($row['nickname'] . '<br/>');
  18. }
  19. }
  20.  
  21. mysql_close($con);
  22. ?>

注,mysql_real_escape_string函数需要连到Mysql服务器才能够工作。

测试一些URL:

  1. http://localhost:8080/test.php?id=3&name=micro
  2.  
  3. PHP version:5.5.30
  4. SQL is:select nickname from user where id = '3' and nickname = 'micro'
  5. rows:1
  6. micro
  7.  
  8. http://localhost:8080/test.php?id=3%27%20or%201=1;%20--%20%27
  9.  
  10. PHP version:5.5.30
  11. SQL is:select nickname from user where id = '3\' or 1=1; -- \'' and nickname = ''
  12. rows:0

讨论上面两个函数里面的漏洞 http://www.t086.com/article/5027:

  1. 主要是针对这个字符:chr(0xbf).chr(0x27).
  2.  
  3. 该漏洞最早2006年被国外用来讨论数据库字符集设为GBK时,0xbf27本身不是一个有效的GBK字符,但经过 addslashes() 转换后变为0xbf5c27
    前面的0xbf5c是个有效的GBK字符,所以0xbf5c27会被当作一个字符0xbf5c和一个单引号来处理,结果漏洞就触发了。
  4.  
  5. mysql_real_escape_string() 也存在相同的问题,只不过相比 addslashes() 它考虑到了用什么字符集来处理,因此可以用相应的字符集来处理字符。
  6. 意思是如果客户端和服务器能够设置一样的字符集,那么可以避免这个漏洞。
  7.  
  8. mysql_real_escape_string检测到的编码方式跟client设置的编码方式(big5/bgk)不一致时,mysql_real_escape_stringaddslashes是没有区别的
  9.  
  10. [client]
  11. default-character-set=latin1
  12. +
  13. mysql_query("SET CHARACTER SET 'gbk'", $mysql_conn);
  14. 这种情况下mysql_real_escape_string 是基于 latin1工作的,是不安全的。
  15.  
  16. [client]
  17. default-character-set=gbk
  18. +
  19. mysql_query("SET CHARACTER SET 'gbk'", $mysql_conn);
  20. 这种情况下mysql_real_escape_string 是基于 gbk工作的,是安全的。
  21. 但是文中作者测试了,仍然是有漏洞的。(存疑)

看了下Mysql 服务器的设置,的确有client这个分组,不过没有加上上面提到的字符集设置:

  1. 位置:
  2. /home/work/.jumbo/etc/mysql/my.cfg
  3.  
  4. 里面关于client的内容:
  5. # The following options will be passed to all MySQL clients
  6. [client]
  7. #password = your_password
  8. port = 8306
  9. socket = /home/work/.jumbo/var/run/mysqld/mysqld.sock

可能是需要加上 default-character-set=gbk 这样的设置吧。不过仍然不是很规范,不推荐。

文章作者还提到,可以用iconv来转换,不过更近粗暴,转不成功后面的就会截断,不太好。另外iconv之后,还需要再加上addslashes函数。

  1. $this->sName=iconv('gbk//IGNORE', 'utf-8', $this->sName);

下面就讨论两个推荐的方式:mysqli 和 PDO,他们的初始方法分别如下所示:

  1. // PDO
  2. $pdo = new PDO("mysql:host=localhost;dbname=database", 'username', 'password');
  3.  
  4. // mysqli, procedural way
  5. $mysqli = mysqli_connect('localhost','username','password','database');
  6.  
  7. // mysqli, object oriented way
  8. $mysqli = new mysqli('localhost','username','password','database');

另外,他们其实也都是有转码的函数的,不过更推荐的是更好的PreparedStatement方式:

  1. 推荐采用prepared statements的方式绑定查询来代替PDO::quote() mysqli_real_escape_string().

看mysqli, PDO是否安装,可以通过php_info()打印出来的信息来看:

  1. http://localhost:8080/index.php
  2. 调用了php_info()
  3.  
  4. API Extensions mysqli,pdo_mysql,mysql
  5.  
  6. mysqli
  7.  
  8. MysqlI Support enabled
  9. Client API library version mysqlnd 5.0.11-dev - 20120503 - $Id: 15d5c781cfcad91193dceae1d2cdd127674ddb3e $
  10. Active Persistent Links 0
  11. Inactive Persistent Links 0
  12. Active Links 0
  13.  
  14. PDO
  15. PDO support enabled
  16. PDO drivers mysql, sqlite
  17.  
  18. 看起来都安装了。

另起一篇,来看mysqli 和 PDO等的操作和对sql注入的处理吧。

SQL注入实验,PHP连接数据库,Mysql查看binlog,PreparedStatement,mysqli, PDO的更多相关文章

  1. 20169205 2016-2017-2 实验四 SQL注入实验

    20169205 2016-2017-2 实验四 SQL注入实验 实验介绍 SQL注入技术是利用web应用程序和数据库服务器之间的接口来篡改网站内容的攻击技术.通过把SQL命令插入到Web表单提交框. ...

  2. 搭建sql注入实验环境(基于windows)

    搭建服务器环境 1.下载xampp包 地址:http://www.apachefriends.org/zh_cn/xampp.html 很多人觉得安装服务器是件不容易的事,特别是要想添加MySql, ...

  3. 第一次MySQL的SQL注入实验

    测试平台:https://www.mozhe.cn/news/detail/324 上完SQL注入的第一节课过来对着笔记一步一步来做.. 1.首页面上没有id=XXX的东西,看见“平台维护通知”,点开 ...

  4. 20169219 SQL注入实验报告

    实验介绍 SQL注入技术是利用web应用程序和数据库服务器之间的接口来篡改网站内容的攻击技术.通过把SQL命令插入到Web表单提交框.输入域名框或页面请求框中,最终欺骗服务器执行恶意的SQL命令. 在 ...

  5. 20169219 SEED SQL注入实验

    实验环境SEED Ubuntu镜像 环境配置 实验需要三样东西,Firefox.apache.phpBB2(镜像中已有): 1.运行Apache Server:只需运行命令sudo service a ...

  6. sql注入攻防 以php+mysql为例

    随着Web应用的高速发展和技术的不断成熟,对Web开发相关职位的需求量也越来越大,越来越多的人加入了Web开发的行列.但是由于程序员的水平参差不齐或是安全意识太低,很多程序员在编写代码时仅考虑了功能上 ...

  7. Collabtive 系统 SQL 注入实验(补充)

    SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. 具体来说,它是利用现有应用程序,将(恶意)的SQL命令注 ...

  8. 登录到mysql查看binlog日志

    查看当前第一个binlog文件的内容 show binlog events; 查看指定binlog文件内容 show binlog events in 'mysql-bin.000002'; 查看当前 ...

  9. mysql查看binlog日志

    1.语法:(用于在二进制日志中显示事件.如果您不指定’log_name’,则显示第一个二进制日志.LIMIT子句和SELECT语句具有相同的语法.) show binlog events [IN 'l ...

随机推荐

  1. DSP中的cmd文件

    一.CMD文件 链接命令文件(Link Command Files),以后缀.cmd结尾,简称CMD文件. CMD文件的两大功能是指示存储空间和分配段到存储空间. 在编写CMD文件时,主要采用MEMO ...

  2. asp.net word ecxel类型文件在线预览

    asp.net word ecxel类型文件在线预览 首先得引用COM: Microsoft Excel 10 Object Library Microsoft Word 10 Object Libr ...

  3. http authorization basic请求代码示例

    /** * */ package testJava.java; import java.io.BufferedReader; import java.io.InputStream; import ja ...

  4. linux gcc++漏洞:普通用户获得root权限

    linux gcc++漏洞:普通用户获得root权限 2012-02-06 10:22:38|  分类: linux安全|举报|字号 订阅       经我测试在RHEL5 / CentOS5 / F ...

  5. 神器——Chrome开发者工具(一)

    这里我假设你用的是Chrome浏览器,如果恰好你做web开发,或者是比较好奇网页中的一些渲染效果并且喜欢折腾,那么你一定知道Chrome的开发者工具了.其实其他浏览器也有类似工具,比如Firefox下 ...

  6. android:scaleType属性

    android:scaleType是控制图片如何resized/moved来匹对ImageView的size. ImageView.ScaleType / android:scaleType值的意义区 ...

  7. NTP服务及时间同步(CentOS6.x)

    博客分类: linux   今有一小型项目,完全自主弄,原来以为很简单的NTP服务,我给折腾了2个多小时才整撑头(以前都是运维搞,没太注意,所以这技术的东西,在简单都需要亲尝啊),这里记录为以后别再浪 ...

  8. NPOI之Excel——合并单元格、设置样式、输入公式

    首先建立一个空白的工作簿用作测试,并在其中建立空白工作表,在表中建立空白行,在行中建立单元格,并填入内容: //建立空白工作簿 IWorkbook workbook = new HSSFWorkboo ...

  9. 李洪强漫谈iOS开发[C语言-006]-程序的描述方式

  10. 使用HTML5实现刮刮卡效果

    你玩过刮刮卡么?一不小心可以中奖的那种.今天我给大家分享一个基于HTML5技术实现的刮刮卡效果,在PC上只需按住鼠标,在手机上你只需按住指头,轻轻刮去图层就可以模拟真实的刮奖效果. 我们利用HTML5 ...