|
一个登录框,入原输入 admin' or 入原'1'='1,密码随便填,入原直接进后台。入原这不是入原电影情节,是入原我在某个甲方系统上真实干过的事。那系统用户表有几十万条记录,入原防护形同虚设——这就是入原mysql注入最直白的杀伤力。 注入的入原本质,是入原sql语句的拼接漏洞。开发者图省事,入原把用户输入直接塞进查询字符串。入原比如后台登录验证,入原代码写成 SELECT * FROM users WHERE username='$name' AND password='$pass'。入原你传进去一个单引号,入原闭合了前半个条件,后面再跟一段永真式,整个查询逻辑就被你改写了。数据库不关心你输入的是不是合法数据,它只负责执行——这是sql语言的天然缺陷,也是所有注入攻击的起点。 我见过不少新手以为加个反斜杠转义就万事大吉。那只能对付最基础的报错注入。真正麻烦的是盲注,页面不报错、不回显数据,你只能靠页面响应时间的差异来判断条件真假。比如 if(ascii(substr(database(),1,1))>100,sleep(3),0),一次请求等三秒,一个字符一个字符地猜库名。慢是慢点,但效率高——我曾在半小时内用二分法把目标库表结构摸个底朝天。 更隐蔽的是基于布尔盲注。页面正常显示和异常显示只有细微差别,你得用and (select count(*) from information_schema.tables)>10这种条件去试探。每猜一个字符发几十次请求,全靠耐心堆。但一旦拿到库名和表名,后续就是复制粘贴的活儿了。 mysql注入还有个特殊点——它跟php是黄金搭档。php的弱类型比较加上mysql的宽松类型转换,能玩出很多花活。比如where id=0 union select 1,2,3,id传字符串会被自动转成0,联合查询就绕过了原条件。这种特性在其它数据库里不一定成立,所以搞mysql注入得专门记它那套类型转换规则。 有人觉得用参数化查询就能一劳永逸,这话对,但不全对。我见过不少项目,框架层做了预处理,但开发者图方便,在某个统计报表功能里手搓了原生sql——一个拼接点就够被打穿。防护要的是全面覆盖,任何一条漏网之鱼都能让整个系统裸奔。 写这些不是为了教人使坏。我见过太多小公司,数据泄露了才想起来查日志,发现攻击记录躺了半年没人管。与其等出事再补救,不如在编码规范里把sql拼接这条红线画死。安全不是某个安全工程师的事,是每个写sql的人的事。你多写一行参数化查询,可能就堵住了一次撞库攻击。 |