Web 应用的安全问题往往不是单一漏洞造成的,而是多个环节的疏忽叠加。攻击者最常利用的入口集中在输入处理、数据库交互和服务器配置三个层面。本文围绕 XSS、SQL 注入以及 Linux 服务器加固展开,梳理常见攻击方式和可落地的防御思路。
XSS 的常见方式与前端防御
XSS(跨站脚本攻击)的本质是攻击者将恶意脚本注入到页面中,使其他用户在浏览时执行。根据注入位置和触发方式,常见类型有三类。
存储型 XSS 是最危险的一种。攻击者将恶意脚本提交到服务器并持久化存储,例如评论区、用户昵称、文章内容。其他用户访问该页面时,脚本自动执行,可窃取 Cookie、伪造请求或篡改页面。
反射型 XSS 通常通过 URL 参数触发。攻击者构造带有恶意脚本的链接,诱导用户点击。服务器将参数直接回显到页面中,脚本随即执行。这类攻击需要用户主动点击,但配合社交工程成功率不低。
DOM 型 XSS 不经过服务器渲染,完全在前端 JavaScript 中发生。例如代码中使用了 innerHTML、document.write、eval 等危险 API,并将用户可控的数据直接插入,就会在浏览器端触发脚本执行。
前端防御的核心原则是:永远不要信任用户输入,输出时进行上下文相关的编码。
- 避免使用
innerHTML、outerHTML、document.write插入不可信内容,优先使用textContent或innerText。 - 如果必须插入 HTML,使用 DOMPurify 等成熟库进行白名单过滤,而不是自己写正则。
- 对 URL 参数、表单输入进行校验和转义,尤其是在拼接 HTML 字符串时。
- 设置
Content-Security-Policy(CSP)响应头,限制脚本来源,禁止内联脚本执行。CSP 是纵深防御的重要手段,即使存在遗漏的注入点,也能大幅降低危害。 - Cookie 设置
HttpOnly和Secure属性,防止脚本读取敏感 Cookie。
需要注意的是,前端防御不能替代后端过滤。攻击者可以绕过前端直接构造请求,因此服务端同样需要对输出进行编码。
MySQL 防止 SQL 注入的几种写法
SQL 注入的根源是用户输入被当作 SQL 代码执行。防御的核心是将数据与指令分离,让用户输入永远只是数据,而不是 SQL 语法的一部分。
第一种:使用预处理语句(Prepared Statements)
这是最推荐的方式。以 PHP PDO 为例:
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');
$stmt->execute(['email' => $email, 'status' => $status]);
$user = $stmt->fetch();
预处理语句先向数据库发送 SQL 模板,再单独发送参数。数据库会明确区分哪些是 SQL 结构,哪些是数据,从根本上杜绝注入。Java 的 PreparedStatement、Python 的 cursor.execute(sql, params)、Node.js 的 connection.execute(sql, params) 都是同样的思路。
第二种:使用 ORM 或查询构建器
Laravel 的 Eloquent、Django ORM、TypeORM 等框架默认使用参数绑定。例如:
User::where('email', $email)->where('status', 'active')->get();
ORM 会自动处理参数转义和绑定,减少手写 SQL 的机会。但要注意,ORM 中的原生查询方法(如 whereRaw)如果拼接字符串,仍然可能引入注入。
第三种:输入验证与白名单
对于无法参数化的部分,例如排序字段、表名,不能使用占位符。此时应采用白名单映射:
$allowed = ['name', 'created_at', 'score'];
$orderBy = in_array($_GET['sort'], $allowed, true) ? $_GET['sort'] : 'created_at';
$sql = "SELECT * FROM users ORDER BY {$orderBy}";
第四种:最小权限原则
数据库账号只授予必要的权限。Web 应用使用的账号不应有 DROP、FILE、GRANT 等权限,即使发生注入,攻击者能造成的破坏也有限。
需要避免的做法包括:直接拼接 SQL 字符串、使用 addslashes 或 mysql_real_escape_string 作为唯一防线、依赖客户端过滤。这些方法在特定编码或字符集下可能被绕过。
Linux 服务器安全加固清单
服务器是 Web 应用的运行底座,加固工作应从账号、网络、服务、日志四个维度展开。
账号与权限
- 禁用 root 远程登录,修改 SSH 端口,使用密钥认证替代密码登录。
- 为每个运维人员分配独立账号,通过
sudo授予必要权限,避免共用账号。 - 定期检查
/etc/passwd和/etc/shadow,清理无用账号和过期账号。 - 设置强密码策略,启用
faillock或pam_tally2限制登录失败次数。
网络与防火墙
- 使用
iptables、nftables或firewalld只开放必要端口,默认拒绝所有入站流量。 - 数据库、Redis、Memcached 等内部服务不要监听公网地址,绑定
127.0.0.1或内网 IP。 - 配置
fail2ban自动封禁暴力破解来源 IP。 - 如果使用云服务器,结合安全组做双层防护。
服务与软件
- 及时更新系统和软件包,订阅安全公告,使用
unattended-upgrades自动安装安全补丁。 - 关闭不必要的服务,使用
systemctl list-unit-files检查开机自启项。 - Web 服务以低权限用户运行,例如
www-data或nginx,禁止以 root 运行。 - 配置 Web 目录权限,上传目录禁止执行脚本,防止上传 WebShell 后直接运行。
- 使用 TLS 证书,禁用过时的 SSLv3、TLS 1.0/1.1,配置 HSTS。
日志与监控
- 开启 SSH、Web 访问、系统认证日志,集中收集到远程日志服务器,防止本地日志被清除。
- 使用
auditd监控关键文件和命令执行。 - 定期检查异常进程、异常网络连接和计划任务(
crontab、systemd timer)。 - 配置告警规则,对暴力破解、异常登录、敏感文件修改及时通知。
备份与恢复
- 定期备份数据库和重要配置,备份文件加密存储并异地保存。
- 定期演练恢复流程,确保备份可用,而不是只备份不验证。
总结
XSS、SQL 注入和服务器配置问题分别对应了 Web 安全的三个层面:前端输出、后端数据访问和基础设施。防御的关键在于不依赖单一措施,而是通过输入验证、参数化查询、CSP、最小权限、日志监控等多层手段形成纵深防御。任何一层被突破时,其他层仍能限制攻击者的行动范围。安全不是一次性的配置,而是持续审查和更新的过程。
未经允许不得转载:任鹏个人博客 » 常见 Web 安全漏洞全景:XSS、SQL 注入与加固思路


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