作为全栈开发者,你可能已经熟练掌握了前后端框架、数据库操作和服务器部署,但安全往往是最容易被忽视的一环。一次 XSS 漏洞可能让用户会话被盗,一个 SQL 注入点可能直接泄露整个数据库,一台未加固的 Linux 服务器可能成为攻击者的跳板。系统学习 Web 安全防御,不是要你成为渗透测试专家,而是要在开发全流程中建立“默认安全”的思维。下面从三个核心维度展开:前端 XSS 防御、MySQL SQL 注入防御、Linux 服务器安全加固。
一、XSS 的常见方式与前端如何防御
XSS(跨站脚本攻击)的本质是攻击者将恶意脚本注入到网页中,当其他用户浏览时执行。常见方式有三种:
- 存储型 XSS:恶意脚本被存入数据库(如评论、昵称),所有访问该页面的用户都会中招。危害最大,常见于论坛、电商评价。
- 反射型 XSS:恶意脚本作为请求参数(如搜索关键词)被服务器直接“反射”回页面,需要诱导用户点击特制链接。
- DOM 型 XSS:不经过服务器,前端 JavaScript 直接从不安全来源(如
location.hash)获取数据并插入 DOM。
前端防御的核心原则:永远不要信任用户输入,永远不要直接拼接 HTML。
具体措施:
- 输出编码:根据插入位置选择编码方式。HTML 内容用 HTML 实体编码(
<→<),属性用引号包裹并编码,JavaScript 上下文用\x转义,URL 用encodeURIComponent。现代框架如 React、Vue 默认对插值进行转义,但dangerouslySetInnerHTML或v-html会绕过保护,必须配合 DOMPurify 等库净化。 - 设置 CSP(内容安全策略):通过 HTTP 头
Content-Security-Policy限制脚本来源,例如script-src 'self'禁止内联脚本和外部恶意域。CSP 是纵深防御的最后一道墙。 - 使用 HttpOnly Cookie:防止 JavaScript 读取会话 Cookie,即使 XSS 发生也无法直接窃取会话。
- 输入验证:对邮箱、URL 等格式做白名单校验,但不要仅依赖前端验证,后端必须重复验证。
记住:前端防御是必要的,但后端输出编码同样不可省略——因为 API 可能被其他客户端调用。
二、MySQL 防止 SQL 注入的几种写法
SQL 注入的根源是用户输入被当作 SQL 代码执行。防御的核心是将数据与指令分离。以下是几种安全写法,按推荐程度排序:
1. 预处理语句(参数化查询)—— 首选方案
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status = ?');
$stmt->execute([$email, $status]);
无论输入什么内容,数据库都将其视为纯数据,不会解析为 SQL 语法。Java 的 PreparedStatement、Python 的 cursor.execute、Node.js 的 mysql2 占位符都同理。
2. 使用 ORM 的安全方法
Laravel Eloquent、Django ORM、TypeORM 等默认使用参数化。但要注意:whereRaw、orderByRaw 等原生方法如果拼接用户输入,依然会注入。应使用绑定参数:
User::whereRaw('email = ?', [$email])->get();
3. 存储过程(需谨慎)
存储过程本身不防注入,只有内部使用参数化查询时才安全。如果存储过程内用 CONCAT 拼接输入,同样会中招。
4. 输入验证与转义(辅助手段)
- 对数字型参数强制转换:
$id = (int)$_GET['id']; - 使用
mysqli_real_escape_string转义特殊字符,但仅适用于旧代码维护,不推荐新项目。 - 最小权限原则:Web 应用使用的数据库账号只授予必要权限(如 SELECT、INSERT),禁止 DROP、FILE 等。
绝对避免:直接拼接字符串,如 "SELECT * FROM users WHERE id = " . $_GET['id']。
三、Linux 服务器安全加固清单
服务器是应用的底座,加固应从“减少攻击面”和“提升入侵成本”入手。以下清单适用于常见的 Ubuntu/CentOS 生产环境:
1. 账户与认证
- 禁用 root 远程登录:
PermitRootLogin no(/etc/ssh/sshd_config) - 使用 SSH 密钥认证,禁用密码登录:
PasswordAuthentication no - 创建普通用户并配置 sudo 权限,避免日常使用 root
- 修改 SSH 默认端口(非必须,但可减少扫描噪音)
2. 网络与防火墙
- 配置 UFW 或 firewalld,仅开放必要端口(如 80、443、自定义 SSH 端口)
- 使用 fail2ban 自动封禁多次登录失败的 IP
- 关闭不需要的服务:
systemctl disable --now cups bluetooth等
3. 系统更新与补丁
- 启用自动安全更新:Ubuntu 用
unattended-upgrades,CentOS 用yum-cron - 定期手动检查内核和关键软件版本
4. 文件权限与审计
- 敏感文件权限最小化:
/etc/shadow应为 640,/etc/ssh/sshd_config为 600 - 使用
chattr +i锁定关键文件(如 /etc/passwd、/etc/shadow)防止篡改 - 部署 auditd 或 OSSEC 监控异常文件变更
5. 日志与监控
- 集中收集
/var/log/auth.log、/var/log/nginx/access.log - 设置告警:如单 IP 短时间内大量 404 或 500 错误
- 定期检查
last、lastb、w命令输出,发现异常登录
6. 应用层配合
- 使用非 root 用户运行 Web 服务(如 www-data)
- 配置 PHP-FPM 或 Node.js 的 open_basedir 限制文件访问
- 定期备份数据库和代码,并测试恢复流程
结语
Web 安全不是一次性任务,而是贯穿开发、部署、运维的持续过程。作为全栈开发者,你不需要记住所有攻击手法,但必须掌握三个核心习惯:对所有输入保持怀疑、对输出进行上下文编码、对系统实施最小权限。从今天起,在每次提交代码前问自己:这个用户输入如果包含恶意内容,会在哪里被执行?这个数据库查询是否可能被拼接?这台服务器如果被入侵,攻击者能走多远?把这三个问题变成肌肉记忆,你就已经超越了大多数开发者。
未经允许不得转载:任鹏个人博客 » 全栈开发者如何系统学习 Web 安全防御


朋友圈点赞图在线生成源码