一个人守一台服务器,没有安全团队,没有预算上企业级设备,怎么把一个公开站点守好?这篇文章记录我实际在做的防护和背后的思路。
先交代总原则:不指望任何单点做到完美,靠分层与纵深——每一层都假设上一层会被突破。攻击者要真的造成伤害,得连续撕开五六道口子;而我在每一层留下的都是"即使失效也不致命"的设计。
一、把入口做小
安全的第一课不是"怎么防",而是"少暴露"。
- 端口最小化:服务器只开放真正需要的端口,且做了双层过滤——云厂商安全组和系统防火墙各拦一道。检查过一遍系统自带的服务,用不到的全部关闭,而不是"留着以后可能用"。
- SSH 只许密钥登录:密码认证直接关掉。公网上对 22 端口的爆破从未停过(日志里每天都有),但密码通道不存在之后,这些尝试在数学上就无效了。
- 服务最小化:跑在机器上的每一个服务都是攻击面。系统默认装的东西,我逐个问自己"我用它吗",不用就停用并禁止被依赖拉起。
二、Web 应用的经典防线
这一层是最容易写错代码的地方,我的做法是把"安全"变成"默认"而不是"记得"。
SQL 注入:全部数据库访问走参数化查询,代码里不允许出现任何一条拼接出来的 SQL。这不是"重要的地方注意一下",而是一行都不留——规范的价值在于它没有例外。
XSS:两道防线。输出侧,所有动态内容统一走转义函数再进页面,这是硬规矩;浏览器侧,上了严格的 CSP,禁止内联脚本和外域脚本。就算哪天某处转义漏了,注入进去的脚本也没有执行环境——这就是纵深:第二道墙不是为了替代第一道,是为了在第一道失效时它还在。
CSRF:所有写操作要求会话令牌,配合 Cookie 的 SameSite 属性。令牌校验用的是恒定时间比较,且拒绝空值——历史上很多框架的绕过恰恰发生在"空令牌与空令牌相等"这种边界上。
权限隔离:后台管理和前台用户是两套完全独立的会话与体系,互不相通。新注册用户一律最低权限,没有任何自动提权逻辑——想要更高权限只能由管理员逐个人工授予。宁可麻烦,不给"抢注成管理员"这类攻击留一寸土壤。
文件上传:这是最容易出 RCE 的地方,我叠了四层——类型白名单、文件内容真实检测、存储时强制随机重命名、目标目录禁止任何脚本执行。每一层单独看都不新鲜,叠起来的意义是:攻击者需要同时绕过全部四层,而其中两层他甚至无法从外部探测。
三、让机器替我盯着的部分
人盯不住日志,但机器可以。
流量的自动监测:服务器持续按小时、按访客维度聚合流量,异常自动分级——轻微的只告警,严重的自动处置。所有判定都在服务端完成,不需要我在线。
处置粒度要小:这是我踩过思路坑的地方。早期设计里"单个来源流量异常"会触发全站紧急停机——后来意识到这等于给了攻击者一个放大器:他刷爆自己的限额,就能让所有人的站点不可用。改造后的原则是:谁异常处置谁,单个来源出问题只封那个来源,全站熔断只保留给真正打穿级别的极端情况,且自动过期解除。
在网关层先挡一道:明显的高频请求在进入应用之前就被限速挡掉,不让它们消耗宝贵的后端并发。应用层再按业务语义做配额——评论有发言冷却、验证码有发送上限、匿名下载有每日次数,让"滥用资源"这件事本身变得无利可图。
四、凭据与数据
- 密码全部用 bcrypt 存储,登录有失败锁定。
- 站点的 API 凭据只存哈希、只在生成时显示一次。丢了只能重新生成——这样数据库哪怕整个泄露,攻击者拿到的也只是一堆不可逆的摘要。
- 下载类接口不发永久直链,而是限时签名链接:过期即失效,无法伪造,也无法分享给别人长期复用。
- 访客统计里存的是加盐哈希后的标识——我需要区分"同一个来源",但不需要知道那具体是谁。隐私和可运维之间,选一个不委屈任何一边的平衡点。
- 数据库每天自动备份,保留多个世代。安全不只是防人,也是防自己手滑。
五、验证一切
以上说的每一条,怎么保证它真的在生效而不是纸面文章?
我给站点建了一套两百项的自动化测试,其中相当一部分就是模拟攻击:注入、越权、伪造、绕过、限速穿透……每次改动后全量跑一遍,任何一项变红就不上线。另外日志里有真实攻击者免费送来的"渗透测试"——扫描探测从来没停过,每一波都是检验防线的机会,我很欢迎。
写在最后
回头看,这些措施没有一条是什么独门秘技,全是工程常识。真正起作用的是几条思路:
- 纵深防御:每层都假设上一层会失败。
- 最小暴露:用不到的端口、服务、权限,一律不存在。
- 自动化:人盯不住的,交给机器,且处置要能自动恢复。
- 处置粒度最小化:别让"防御行为"本身变成可被利用的攻击面。
- 持续验证:防护不是配置完就结束,是要用测试和真实流量反复证明的。
一个人守一台服务器,靠的不是多高明,是不偷懒、不侥幸。
本文只讲防护思路与做法,不涉及任何具体参数与实现细节。
m1SuHub