PHP全栈安全实战:SQL注入深度防护
|
工位上的键盘声吵得我头疼,手机又亮了一下——工单系统弹了条高危告警,SQL注入攻击,目标是我们组去年重构的订单查询接口。我盯着屏幕上的攻击日志,参数里那串`' OR 1=1 --`刺得眼睛发酸。运维在群里喊:“谁写的SQL没防注入?QPS都掉到地上了!”我原以为参数校验那层已经够厚了,结果还是被钻了空子。 这事得从二零二六年一月的某个凌晨说起。当时前端突然甩过来一个需求:“用户反馈搜索订单时,输入特殊字符会报错。”我翻了下日志,发现有人往搜索框里塞了`' AND sleep(5) --`,直接触发了MySQL的延迟注入。我第一反应是:“这前端不校验输入吗?”结果前端小哥回:“我们只做格式校验,安全不是你们后端的事?”我差点把咖啡喷在键盘上——这逻辑跟“我只负责开门,防盗是锁的事”有什么区别?
文章配图,仅供参考 后来查代码,发现老同事留下的“祖传代码”里,订单查询的SQL是直接拼的字符串。比如:```php $sql = "SELECT FROM orders WHERE user_id = '$user_id' AND status = '$status'"; ``` 我原以为这种写法早被淘汰了,结果翻历史提交记录,发现这代码从二零一八年就开始跑,中间换过三个人维护,没人敢动它——怕改出问题。更离谱的是,参数里连最基本的`addslashes()`都没加,直接裸奔。我试着在本地模拟攻击,输入`' OR 1=1 --`,果然返回了所有订单数据。这要是被黑产扫到,分分钟能把数据库拖空。 咖啡凉了,我搓了搓脸,开始改代码。第一步是把所有直接拼SQL的地方换成预处理语句。PHP的PDO其实挺方便,改起来不算难: ```php $stmt = $pdo->prepare("SELECT FROM orders WHERE user_id = ? AND status = ?"); $stmt->execute([$user_id, $status]); ``` 但改着改着就发现问题了——有些查询条件是动态生成的,比如用户可能只搜订单号,也可能同时搜状态和时间范围。这时候预处理语句的占位符数量会变,代码写得特别丑。我试了用`call_user_func_array()`动态绑定参数,结果调试了半小时,发现参数顺序对不上,直接报错。最后没办法,只能写了个丑陋的`if-else`分支,根据条件数量拼不同的SQL模板。前端小哥路过时瞥了一眼,说了句:“这代码比我爷爷的假牙还乱。” 改完动态查询,我以为万事大吉了,结果测试同学又甩过来一个案例:用户在搜索框里输入了`1'; DROP TABLE orders; --`。我盯着屏幕愣了三秒——这他妈是SQL注入的经典案例啊!预处理语句能防参数注入,但防不了这种直接拼到SQL里的恶意字符串。我翻了下代码,发现有个地方为了“灵活”,把用户输入的搜索词直接拼进了`LIKE`条件里: ```php $search = $_GET['search']; $sql = "SELECT FROM orders WHERE title LIKE '%$search%'"; ``` 我当场骂出声:“这他妈是谁写的?!”运维在隔壁工位探头:“好像是去年离职的老张?”我翻了下提交记录,果然是他——那个总说“安全是运维的事”的老油条。这时候产品经理凑过来:“这个搜索功能能加个模糊匹配吗?用户反馈不好用。”我盯着他:“先保证不被拖库再说模糊匹配。” 最后解决方案是:所有用户输入必须先过白名单校验,再转义特殊字符。比如搜索词只能包含字母、数字和中文,其他字符一律过滤;如果必须用`LIKE`,就用`str_replace()`把单引号换成双引号(MySQL里双引号不会触发注入)。我原以为这样就够了,结果测试同学又发现个漏洞:如果用户输入`%`,`LIKE '%%'`会匹配所有记录,相当于绕过了查询条件。我叹了口气,又在白名单里加了条规则:搜索词不能以`%`开头或结尾。前端小哥吐槽:“这哪是搜索框,这是密码输入框吧?” 改完这些,天已经黑了。我提交了代码,等着CI跑测试。运维在群里发消息:“攻击流量停了,应该是对方发现不好搞,换目标了。”我松了口气,但心里还是发虚——这次是运气好,攻击者没死磕,下次呢?我翻了翻其他项目的代码,发现还有好几个地方在用裸拼SQL,甚至有个内部管理后台的登录接口,密码是直接拼进SQL里查的。我拍了张代码截图发到群里:“这谁写的?明天来我工位喝茶。” 其实说白了,SQL注入这事儿,优胜劣汰的逻辑特别明显。那些用预处理语句、严格校验输入的项目,活得好好的;那些靠“运气”或者“老代码稳定”的项目,早晚会被攻击者盯上。我原以为安全是“额外的事”,结果发现它就是代码的“基础属性”——就像房子得有地基,车得有刹车,少了它,早晚得出事。 现在的问题是,怎么让其他同事意识到这点?前端觉得安全是后端的事,运维觉得安全是开发的事,产品觉得安全是“阻碍需求”的借口。我盯着屏幕上的攻击日志,突然有点迷茫——下次攻击来的时候,我们真的能防住吗?或者,我们只是暂时没被盯上而已? (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

