一、Web 安全的核心原则
在讨论具体漏洞之前,先记住几个基本原则:
- 永不信任用户输入
所有来自浏览器、API、文件、Header、Cookie 的数据都可能被伪造。 - 最小权限
数据库账号、系统账号、容器权限、云密钥都应只拥有完成工作所需的最小权限。 - 纵深防御
不要只依赖一层防护。输入验证、输出编码、WAF、权限校验、日志监控应同时存在。 - 默认安全
默认拒绝、默认关闭调试、默认启用 HTTPS、默认最小暴露面。 - 失败安全
出错时不应绕过安全检查,而应拒绝请求并记录日志。 - 可观测性
没有日志、监控和告警,就无法发现入侵和异常行为。
二、OWASP Top 10 视角:常见漏洞与防护
OWASP Top 10 是 Web 安全领域广泛参考的风险清单。以下用简表概括常见风险与防护方向。
| 风险 | 典型问题 | 防护要点 |
|---|---|---|
| 访问控制失效 | 水平越权、垂直越权 | 服务端鉴权、资源归属校验、默认拒绝 |
| 加密失败 | 明文传输、弱哈希、密钥泄露 | HTTPS、HSTS、强哈希、KMS 管理 |
| 注入 | SQL 注入、命令注入 | 参数化查询、白名单、最小权限 |
| 不安全设计 | 业务逻辑缺陷 | 威胁建模、滥用场景分析 |
| 安全配置错误 | 默认口令、调试开启、CORS 过宽 | 加固基线、关闭调试、最小暴露 |
| 脆弱过时组件 | 依赖库漏洞 | SCA 扫描、及时更新、锁定版本 |
| 身份认证失败 | 弱密码、撞库、会话固定 | MFA、限速、安全 Cookie、会话轮换 |
| 软件和数据完整性失败 | 供应链篡改 | 签名、校验、CI/CD 权限控制 |
| 日志监控失败 | 无审计、无告警 | 集中日志、异常告警、保留证据 |
| SSRF | 服务端请求伪造 | URL 白名单、禁止内网、网络隔离 |
其中,注入类漏洞最经典的防护方式就是参数化查询。例如:
python
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
不要拼接 SQL 字符串。参数化查询能让数据库区分“代码”和“数据”,从而阻断注入。
三、前端安全:XSS、CSRF 与点击劫持
前端是用户直接接触的界面,也是攻击者常利用的入口。
1. XSS 跨站脚本
XSS 的本质是攻击者让恶意脚本在其他用户浏览器中执行。常见类型包括存储型、反射型和 DOM 型。
防护重点:
- 对输出进行上下文编码,而不是只做输入过滤。
- 使用 CSP 限制脚本来源。
- 富文本使用白名单过滤。
- Cookie 设置
HttpOnly,降低脚本窃取会话的风险。
一个简化的 CSP 响应头示例:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'
这表示默认只允许同源资源,脚本只允许同源,禁止插件对象,并禁止被嵌套。
2. CSRF 跨站请求伪造
CSRF 利用用户已登录的会话,诱导其浏览器发起非预期请求。
防护重点:
- 使用 CSRF Token,并在服务端校验。
- Cookie 设置
SameSite=Lax或Strict。 - 校验
Origin和Referer。 - 对敏感操作要求二次确认或重新认证。
安全的会话 Cookie 示例:
Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax
3. 点击劫持
攻击者用透明 iframe 覆盖页面,诱导用户点击。防护可使用:
X-Frame-Options: DENY- CSP 的
frame-ancestors 'none'
四、后端与 API 安全
后端是权限和数据的最后防线。API 安全尤其重要,因为很多移动端、前端和第三方系统都直接调用 API。
关键措施:
- 认证
使用成熟协议,如 OAuth 2.0、OpenID Connect。JWT 要校验签名、过期时间、发行者和受众,不要信任未验证的令牌。 - 授权
每个接口都要校验“当前用户是否有权访问该资源”。不要只在前端隐藏按钮。 - 输入验证
对类型、长度、范围、格式做白名单校验。文件上传要限制类型、大小,并隔离存储。 - 错误处理
对外返回统一错误信息,不暴露堆栈、SQL、内部路径。 - 速率限制
对登录、注册、短信、支付等接口限速,防止撞库和自动化滥用。 - 反序列化安全
避免反序列化不可信数据,优先使用 JSON 等简单格式。
五、数据与密码安全
数据是攻击者的最终目标。
- 传输安全:全站 HTTPS,启用 HSTS,避免混合内容。
- 密码存储:使用 Argon2、bcrypt 等专用算法,加盐,不可逆。
- 敏感数据加密:身份证、银行卡等敏感字段应加密存储,密钥放入 KMS 或密钥管理系统。
- 备份安全:备份加密,访问受限,定期恢复演练。
密码哈希的简化示例:
python
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
不要使用 MD5、SHA1 或普通 SHA256 直接存密码。它们速度太快,容易被暴力破解。
六、安全开发流程
安全要左移,也就是尽早进入研发流程。
- 需求阶段:明确安全需求、合规要求和数据分级。
- 设计阶段:进行威胁建模,识别资产、信任边界和攻击路径。
- 开发阶段:制定安全编码规范,开展代码评审。
- 测试阶段:结合 SAST、DAST、SCA、IAST 和人工渗透测试。
- 发布阶段:CI/CD 中加入安全门禁,制品签名,限制发布权限。
- 运维阶段:持续监控、补丁管理、日志审计和应急演练。
安全不是“上线前扫一次”,而是持续循环。
七、部署与运维安全
生产环境的安全配置同样关键。
- 启用安全响应头:CSP、HSTS、
X-Content-Type-Options、Referrer-Policy。 - 使用 WAF 和限速,但不能只依赖 WAF。
- 数据库、缓存、消息队列不要直接暴露公网。
- 容器使用非 root 用户,限制能力,镜像最小化。
- 云上使用最小权限 IAM,避免长期密钥。
- 集中日志,设置异常告警,如多次登录失败、异常出口流量、敏感接口高频访问。
- 定期备份,并验证恢复流程。
八、应急响应
即使防护完善,也要假设可能被突破。应急响应通常包括:
- 准备:预案、联系人、工具、权限。
- 检测:通过日志、告警、流量分析发现异常。
- 遏制:隔离主机、封禁 IP、吊销密钥、下线接口。
- 根除:修复漏洞、清除后门、更新补丁。
- 恢复:从干净备份恢复,持续监控。
- 复盘:分析原因,改进流程,必要时通知用户和监管机构。
保留证据很重要,不要急于删除日志或重装系统。
九、结语
Web 安全没有银弹。真正有效的做法,是把安全融入日常研发和运维:默认拒绝、最小权限、参数化查询、输出编码、HTTPS、MFA、依赖扫描、日志告警和应急演练。
如果只能从今天开始做几件事,建议优先:
- 全站 HTTPS 和 HSTS。
- 所有数据库查询使用参数化。
- 所有输出按上下文编码,并配置 CSP。
- 登录启用 MFA 和限速。
- 定期扫描依赖漏洞。
- 建立日志、监控和告警。
安全的目标不是“永远不被攻击”,而是让攻击成本更高、发现更快、损失更小。