深入浅出MySQL SQL中的安全问题

SQL 中的安全问题

​ 在日常开发过程中,程序员一般只关心 SQL 是否能实现预期的功能,而对于 SQL 的安全问题一般都不太重视.实际上,如果SQL语句写作不当,将会给应用系统造成很大的安全隐患,其中最重要的隐患就是 SQL 注入。本章以MySQL为例,将会对 SQL 注入以及相应的防范措施进行详细的介绍。

SQL 注入简介

​ 结构化查询语言(SQL)是一种用来和数据库交互的文本语言。SQL 注入 (SQL Injection)就是利用某些数据库的外部接口将用户数据插入到实际的数据库操作语言(SQL)中,从而达到入侵数据库乃至操作系统的目的。它的产生主要是由于程序员对用户输入的数据没有进行严格的过滤,导致非法数据库查询语句的执行。

​ SQL 注入攻击具有很大危害,攻击者可以利用它读取、修改或者删除数据库内的数据,获取数据库中的用户名和密码等敏感的信息,甚至可以获得数据库管理员的权限,而且,SQL注入也很难防范。网站管理员无法通过安装系统补丁或者进行简单的安全配置进行自我保护,一般的防火墙也无法拦截SQL注入攻击。

​ 下面的用户登录验证程序就是 SQL 注入的一个例子(Java):

​ (1)创建用户表 user:

create table user (
	userid int(11) not null auto_increment,
    username varchar(20) not null default '',
    password varchar(20) not null default '',
    primary key (userid)
) ENGINE=MyISAM auto_increment=3;
# auto_increment=3; 从3开始

​ (2)给用户表添加一条用户记录

mysql> insert into user values (1, 'angel', 'mypass');
Query OK, 1 row affected (0.01 sec)

​ (3)验证用户登录服务器:

username=angel 'or' 1=1

​ 结果发现,这个可以成功登录系统,因为在SQL语句中,“/*” 或者 “#” 都可以将后面的语句注释掉。

应用开发中可以采取的应对措施

​ 对于上面提到的SQL注入隐患,后果可想而知是很严重的,轻则获得数据信息,重则可以将数据进行非法更改。

PrepareStatement + Bind-Variable

​ MySQL服务器端并不存在共享池的概念,所以在MySQL上使用绑定变量(Bind Variable)最大的好处主要是为了避免SQL注入,增加安全性。下面以Java语言为例。

Class.forName("com.mysql,jdbc.Driver").newInstance();
String url = "jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, username, password);
String sql = "select * from user where username=? and password=?";
System.out.println("source sql statement:" + sql);
PrepareStatement ps = connection.prpareStatement(sql);
System.out.println("before bind variable:" + ps.toString());
ps.set(1, "angel 'or' 1=1");
ps.set(2, "123456");
System.out.println("after bind variable:" + ps.toString());

....    

​ 需要注意的是,PrepareStatement 语句是由 JDBC驱动来支持的,在使用 PrepareStatement 语句的时候,仅仅做了简单的替换和转义,并不是MySQL提供了 PrepareStatement 的特性。

使用应用程序提供的转换函数

​ 很多应用程序接口都提供了对特殊字符进行转换的函数。恰当地使用这些函数,可以防止应用程序用户输入使应用程序生成不期望的语句。

  • MySQL C API:使用 mysql_real_escape_string() API 调用。
  • MySQL++ :使用 escape 和 quote 修饰符。
  • PHP:使用 mysql_real_escape_string() 函数(适用于PHP 4.0.3 版本)。从PHP5 开始,可以使用扩展的MySQLI,这是对MySQL新特性的一个扩展支持,其中的一个优点就是支持PrepareStatement。
  • Perl DBI:使用 placeholders 或者 quote() 方法。
  • Ruby DBI:使用 placeholders 或者 quote() 方法。

自定义函数进行校验

​ 如果现有的转换函数任然不能满足要求,则需要自己编写函数进行输入验证。输入验证是一个很复杂的问题。输入验证的途径可以分为以下几种:

  1. 整理数据使之变得有效;
  2. 拒绝已知的非法输入;
  3. 只接受已知的合法输入;

​ 因此,如果想要获得最好的安全状态,目前最好的解决办法就是,对用户提交或者可能改变的数据进行简单分类,分别应用正则表达式来对用户提供的输入数据进行严格的检测和验证。

​ 下面采用正则表达式的方法提供一个验证函数:

​ 已知非法符号有:

"," ";" "=" "(" ")" "/*" "*/" "%" "+" "" ">" "<" "--" "[""]"

​ 其实只需要过滤非法的符号组合就可以阻止已知形式的攻击,并且如果发现更新的攻击符号组合,也可以将这些符号组合添加进来,继续防范新的攻击。特别时空格符号和与其产生相同作用的分隔关键字的符号,例如“/**/” ,如果能成功过滤这种符号,那么有很多注入攻击将不能发生,并且同时也要过滤它们的十六进制表示“%XX”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值