接手一台服务器,别急着上架业务。默认的操作系统安装和中间件配置,往往为了通用性而牺牲了安全性。服务端漏洞的根源,绝大多数时候不在于黑客技术有多高明,而在于管理员忽略了配置文件中几个不起眼的参数,或者没有及时给某个组件打上补丁。这是一场不对等的战争,防守方必须堵住所有缺口,攻击者只需找到一个。下面直接进入具体的检测与加固操作,从操作系统层到应用层,逐一拆解。

操作系统层基线检测与加固

拿到一台Linux服务器,先做三件事:检查账户体系、审计权限、锁定关键文件。不要使用root账户进行日常运维,这是铁律。立即创建一个普通用户并授予sudo权限,命令如下:

adduser deploy
usermod -aG sudo deploy

随后,编辑/etc/ssh/sshd_config文件,禁止root远程登录,并更改默认的22端口。将PermitRootLogin设为no,Port设为一个高位端口,例如2222。同时,如果条件允许,直接禁用密码登录,全部改用密钥对认证。PasswordAuthentication no这行配置,能挡住90%的自动化暴力破解扫描。修改完重启sshd服务即可生效。

文件权限的加固往往被低估。检查系统中所有带有SUID和SGID权限的文件,这些文件是提权攻击的温床。使用命令find / -perm -4000 -o -perm -2000 2>/dev/null进行排查。对于不需要特殊权限的程序,果断执行chmod -s去除。特别是像/usr/bin/passwd这类必须保留SUID的文件,要确保其md5sum值与官方发行版一致,防止被植入后门。

Web中间件与数据库的配置陷阱

Nginx和Apache的配置文件里藏着大量信息泄露点。以Nginx为例,在nginx.conf的http块中添加server_tokens off;,可以隐藏版本号。但更重要的是,检查是否配置了错误的目录遍历漏洞。很多运维习惯在location中配置autoindex on;来方便查看文件,这在生产环境是致命的。必须将其设为off,并确保每个站点目录下没有遗留的备份文件,比如常见的vim交换文件*.swp或压缩包备份*.tar.gz。

数据库方面,MySQL或PostgreSQL安装完成后,第一件事不是创建业务库,而是运行安全初始化脚本。对于MySQL,执行mysql_secure_installation,移除匿名用户、禁止远程root登录、删除测试数据库。如果业务必须开放远程连接,务必使用防火墙限定来源IP,而不是直接对所有地址开放3306端口。在应用程序的数据库连接配置中,遵循最小权限原则,仅授予业务所需的SELECT、INSERT、UPDATE权限,绝不赋予DROP或ALTER权限给普通应用账户。

应用层注入攻击的深度防御

SQL注入已经存在了二十年,至今仍在漏洞排行榜前列,原因在于开发者对输入边界的漠视。不要依赖全局过滤器,那只能防住初学者。真正的加固在代码层。所有拼接SQL的写法都应被视为违规。无论后端是Java还是Python,强制使用参数化查询。在Java的JDBC PreparedStatement中,用问号占位符传递变量;在Python的Django ORM中,坚持使用filter()而非raw()。如果业务场景确实需要动态表名或列名,必须建立白名单映射,绝不允许用户输入直接进入SQL语句。

除了SQL注入,命令注入同样危险。当业务代码中调用了system、exec、popen等函数时,要立刻警觉。审查代码时,搜索这些关键字,确认参数是否来自用户输入。如果必须执行外部命令,例如图片处理调用ImageMagick,应使用参数数组的方式传递,避免使用shell解析器。在PHP中,escapeshellarg()函数是必须的,但更彻底的做法是完全避免在Web应用中执行系统命令,将这类任务交给后台队列异步处理。

文件上传功能的严苛管控

文件上传点是服务端最脆弱的入口之一。不要只在前端验证文件类型,攻击者用Burp Suite抓包即可绕过。后端验证必须做到三点:文件扩展名白名单、文件内容幻数检测、上传目录不可执行。白名单要严格到只允许.jpg、.png、.pdf这类确需的类型,拒绝.php、.jsp、.asp哪怕是在文件名中间出现。使用file命令或读取文件头几个字节来校验MIME类型,而不是轻信HTTP请求中的Content-Type头。

存储上传文件的目录,必须配置为禁止脚本引擎解析。在Nginx中,对该目录的location块添加以下配置:

location /uploads {
    location ~ .*\.(php|php5)?$ {
        deny all;
    }
}

在Apache中,可以通过.htaccess文件设置php_flag engine off。更稳妥的做法是将文件存储在Web根目录之外,通过一个专门的读取接口来输出文件流,这样即使上传了恶意脚本,也根本没有直接访问的URL路径。

会话管理与认证机制的加固

登录功能是暴力破解和会话劫持的重灾区。验证码不能只是摆设,如果验证码的答案直接输出在响应包的Cookie或隐藏字段中,等于形同虚设。检查登录失败次数限制,不能仅基于IP地址,因为攻击者会使用代理池。应该结合账户名进行锁定,连续5次失败后,强制要求通过邮箱或手机验证码解锁。对于生成的会话ID,确保其具备足够的随机性和长度,且在整个HTTPS会话中,Cookie必须设置Secure、HttpOnly和SameSite属性。在Tomcat等容器中,修改session-config配置,强制开启这些标记。

如果有API接口,绝对不要使用HTTP Basic Authentication这种每次请求都传输用户名密码的方式。采用基于令牌的认证,JWT是常见选择,但实现细节决定安全性。JWT的签名算法必须设为非对称的RS256,而不是对称的HS256,因为HS256的密钥如果泄露,攻击者可以伪造任意令牌。同时,令牌的过期时间要尽可能短,配合刷新令牌机制使用,绝不签发永久有效的令牌。

第三方组件与依赖库的漏洞排查

现代Web应用90%的代码来自开源组件,这意味着你的攻击面大部分由第三方决定。建立持续性的依赖扫描流程,比事后修补更重要。对于Java项目,使用Maven或Gradle的插件检查pom.xml中的依赖是否有已知CVE漏洞。对于Node.js项目,npm audit命令能快速列出风险包,但不要止步于此,很多原型污染或拒绝服务漏洞的严重性被标记为中等,实际在特定业务场景下可能是高危。当发现fastjson、log4j这类基础组件有漏洞时,升级版本是唯一选择,任何基于配置的临时修复都可能在绕过技术面前失效。

尤其要注意那些看似无害的富文本编辑器或文件解析库。它们处理的数据格式复杂,容易出现解析漏洞。例如,允许用户上传Office文档并在线预览的服务,底层的LibreOffice或Apache POI库必须保持最新。如果暂时无法升级,就在独立的沙箱环境中运行解析任务,限制其网络访问和文件系统写入权限,即使被攻破也无法横向移动。

日志审计与实时告警的闭环

没有监控的安全是假安全。加固完成后,必须验证日志是否记录了关键事件。至少确保登录成功与失败、权限变更、敏感操作都有日志输出。将应用日志、中间件日志和系统日志统一接入日志中心,使用ELK或类似工具进行聚合。设置告警规则,例如同一账户一分钟内登录失败超过10次、某个IP尝试访问大量不存在的路径、或者Web服务器突然返回大量500错误。这些异常行为往往是攻击前兆。

定期进行漏洞扫描和渗透测试,把扫描器当成一个挑剔的审计员。使用OpenVAS对服务器进行全端口扫描,用Nikto检查Web服务的配置缺陷,再用SQLMap对关键API接口做自动化注入测试。每次测试后生成的报告,就是下一轮加固的起点。安全是一个循环迭代的过程,今天的加固基线,可能明天就会被新披露的攻击手法绕过。保持对安全公告的关注,建立快速响应机制,才能在攻防对抗中争取主动。