《安全漏洞游戏》
凌晨三点,安全我盯着屏幕上那行报错,漏洞心里一阵发毛。游戏不是安全崩溃,是漏洞权限绕过。一个普通用户,游戏在没登录的安全情况下,拿到了管理员接口的漏洞返回数据。
这不是游戏什么高深攻击,就是安全参数里多写了一个 user_id=0。后端没校验,漏洞直接查了库。游戏开发者当时大概想的安全是“反正前端不会传这个值”。
安全漏洞很多时候就这么无聊。漏洞它不像电影里那样满屏代码乱飞,游戏更像你忘了关窗户,而风刚好把门吹开了。
我后来养成一个习惯:每次写完接口,先自己当坏人。不是用扫描器,那玩意儿只会告诉你“可能存在XSS”,但不会告诉你这个XSS能不能偷到cookie。我会拿Burp抓包,改几个字段,试试删掉token还能不能访问,试试把 id=1 换成 id=1 or 1=1,试试上传一个 .php.jpg 文件。多数时候没事,但偶尔,就那么一两次,你会发现一个洞。那种感觉像在旧外套口袋里摸到一张百元钞——惊喜,但紧接着是后怕。
有次帮朋友看一个后台。登录框很朴素,用户名密码。我试了 admin' --,页面直接跳转进首页。他站在旁边,脸都白了。数据库是五年前的老版本,没做预处理。这个洞在他系统里躺了三年,每天有人登录,没人发现。因为正常用户不会在密码框里打单引号。
这就是漏洞的吊诡之处。它一直在那儿,但只有你以错误的姿势去碰,它才显形。日常使用中,它几乎不存在。可一旦有人故意去找,它就像没锁的抽屉,一拉就开。
我见过最离谱的一个,是重置密码的接口。请求里带手机号和验证码,但验证码校验逻辑写错了——只要验证码长度是6位,就通过。我随便填了 000000,密码重置成功。开发者后来解释,说测试时一直用真实验证码,没试过假的。你看,连开发者自己都没“错误地”用过这个功能。
安全测试和功能测试的区别就在这。功能测试问“这个按钮点了有没有反应”,安全测试问“我不点这个按钮,直接发请求行不行”。前者是顺着路走,后者是翻墙。
翻多了会发现,大部分漏洞不来自复杂逻辑,来自偷懒。比如权限校验只在前端做,后端觉得“反正前端已经拦了”。比如文件上传只检查Content-Type,改个请求头就绕过了。比如数据库查询直接拼字符串,因为“内部系统没人攻击”。
这些偷懒在业务快速迭代时几乎不可避免。产品催着上线,测试只跑主流程,安全评审?那是大公司才有的流程。小团队能按时发版就不错了。
所以漏洞像野草。你拔掉一茬,下一版新功能又带进来一茬。没有一劳永逸。我现在的做法很笨:每次上线前,拿OWASP Top 10过一遍,不追求全懂,就检查那几个最常见的——注入、越权、敏感信息泄露。花二十分钟,能挡住八成脚本小子的扫描。
剩下的两成,靠运气,也靠半夜三点那行报错提醒你:嘿,窗户没关。