用bunjs代码讲解XSS/CSRF/SQL注入/DDos等10种前后端安全防护

我40岁了, 还在写javascript

攻击清单(10 种)

  • SQL 注入 -- 插入恶意 SQL 语句
  • XSS -- 注入恶意脚本
  • CSRF -- 伪造跨站请求
  • 弱密码撞库 -- 破解或撞库
  • 文件上传漏洞 -- 上传恶意文件
  • 路径遍历 -- ../ 访问敏感文件
  • 中间人攻击 -- 拦截通信数据
  • 点击劫持 -- 透明 iframe 诱导点击
  • DDoS / 暴力破解 -- 海量请求耗尽资源
  • WebSocket 劫持 -- 劫持实时通信

1. SQL 注入 -- 参数化查询

核心代码

ts 复制代码
const userInput = ['张三', '男', '19']
db.query('SELECT * FROM users WHERE name = ? AND sex = ? AND age = ?', userInput)
// 实际执行的 SQL:SELECT * FROM users WHERE name = '张三' AND sex = '男' AND age = '19'

? 是占位符,数组按顺序替换 ?。数据库驱动自动转义特殊字符(如 '),输入只作为数据,不改变 SQL 结构。

注入攻击示例

攻击者在用户名输入框中输入:

text 复制代码
' OR '1'='1

错误写法(字符串拼接)

ts 复制代码
const sql = `SELECT * FROM users WHERE name = '${userName}'`
// 生成的 SQL:SELECT * FROM users WHERE name = '' OR '1'='1'

由于 '1'='1' 永远为真,返回所有用户,攻击成功。

正确写法(参数化查询)

ts 复制代码
db.query('SELECT * FROM users WHERE name = ?', [userName])
// 实际执行的 SQL:SELECT * FROM users WHERE name = '\' OR \'1\'=\'1'

整个输入被当作普通字符串,无法篡改查询逻辑,攻击无效。

结论 :永远使用 ? 占位符 + 数组传参,杜绝 SQL 注入。

2. XSS(跨站脚本)-- 输出转义 + textContent

后端(输出转义)

ts 复制代码
import { Elysia } from 'elysia'

// 转义 HTML 特殊字符,防止浏览器将用户输入当作代码执行
const escapeHtml = (s: string) =>
  s.replace(/[&<>]/g, (m) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' })[m] || m)

new Elysia()
  .get('/hello', ({ query }) => {
    const safe = escapeHtml(query.name || 'guest')
    return `<h1>Hello ${safe}</h1>`
  })
  .listen(3000)

前端(使用 textContent 而非 innerHTML)

html 复制代码
<div id="out"></div>
<script>
  fetch('/hello?name=<script>alert(1)</script>')
    .then(r => r.text())
    .then(html => {
      document.getElementById('out').textContent = html  // 不会执行脚本
    })
</script>

后端(Bun.CSRF + sameSite: 'lax')

ts 复制代码
import { Elysia } from 'elysia'

const csrfStore = new Map()

new Elysia()
  .get('/form', ({ cookie, setCookie }) => {
    const sid = cookie.sessionId?.value || crypto.randomUUID()
    setCookie('sessionId', sid, { httpOnly: true, sameSite: 'lax' })
    const { token } = Bun.CSRF.generateToken()
    csrfStore.set(sid, token)
    return `
      <form action="/transfer" method="POST">
        <input name="csrf" value="${token}">
        <button>转账</button>
      </form>
    `
  })
  .post('/transfer', ({ body, cookie }) => {
    const valid = Bun.CSRF.verifyToken(body.csrf, csrfStore.get(cookie.sessionId?.value))
    if (!valid) return new Response('CSRF无效', { status: 403 })
    return '转账成功'
  })
  .listen(3000)

前端 :表单自动携带隐藏 csrf 字段;AJAX 时手动加到 X-CSRF-Token 头。

4. 弱密码与撞库 -- 强哈希(Argon2id)

后端(Bun.password.hash 默认 Argon2id)

ts 复制代码
import { Elysia } from 'elysia'

new Elysia()
  .post('/register', async ({ body }) => {
    const hash = await Bun.password.hash(body.password)  // Argon2id 慢哈希
    // 存储 hash...
    return { ok: true }
  })
  .listen(3000)

前端:可加 zxcvbn 强度提示(非必需)。

5. 文件上传漏洞 -- 白名单 + 随机名 + 大小限制

后端

ts 复制代码
import { Elysia } from 'elysia'

new Elysia()
  .post('/upload', async ({ body }) => {
    const file = body.file as File
    if (!['image/jpeg', 'image/png'].includes(file.type))
      return new Response('类型错误', { status: 400 })
    if (file.size > 5 * 1024 * 1024)
      return new Response('文件过大', { status: 400 })
    const ext = file.name.split('.').pop()
    const newName = `${crypto.randomUUID()}.${ext}`
    await Bun.write(`./uploads/${newName}`, file)
    return { name: newName }
  })
  .listen(3000)

前端

html 复制代码
<input type="file" id="upload" accept="image/jpeg,image/png">
<button onclick="uploadFile()">上传</button>
<script>
  async function uploadFile() {
    const file = document.getElementById('upload').files[0]
    if (file.size > 5 * 1024 * 1024) return alert('文件不能超过5MB')
    const fd = new FormData()
    fd.append('file', file)
    await fetch('/upload', { method: 'POST', body: fd })
  }
</script>

6. 路径遍历(目录穿越)-- 路径规范化 + 根目录检查

后端

ts 复制代码
import { Elysia } from 'elysia'
import { resolve, normalize } from 'path'

new Elysia()
  .get('/files/*', ({ params, set }) => {
    const reqPath = params['*']
    const full = resolve('./public', normalize(reqPath))
    if (!full.startsWith(resolve('./public'))) {
      set.status = 403
      return 'Forbidden'
    }
    return Bun.file(full)
  })
  .listen(3000)

前端:无特殊配合。

7. 中间人攻击(MITM)-- HSTS + 强制 HTTPS

后端

ts 复制代码
import { Elysia } from 'elysia'

new Elysia()
  .onBeforeHandle(({ set, request }) => {
    if (request.headers.get('x-forwarded-proto') !== 'https') {
      return new Response('请使用 HTTPS', { status: 403 })
    }
    set.headers['Strict-Transport-Security'] = 'max-age=31536000'
  })
  .listen(3000)

前端 :所有 API 请求使用 https://

8. 点击劫持 -- X-Frame-Options

后端

ts 复制代码
import { Elysia } from 'elysia'

new Elysia()
  .onBeforeHandle(({ set }) => {
    set.headers['X-Frame-Options'] = 'DENY'
  })
  .listen(3000)

前端:无需配合。

9. DDoS / 暴力破解 -- 限速库(@elysiajs/rate-limit)

安装

bash 复制代码
bun add @elysiajs/rate-limit

后端

ts 复制代码
import { Elysia } from 'elysia'
import { rateLimit } from '@elysiajs/rate-limit'

new Elysia()
  .use(rateLimit({ max: 10, duration: 60000 }))
  .post('/login', () => '登录成功')
  .listen(3000)

前端(指数退避)

js 复制代码
async function retryFetch(url, opts, attempt = 3) {
  const res = await fetch(url, opts)
  if (res.status === 429 && attempt > 0) {
    const delay = 1000 * (4 - attempt)
    await new Promise(r => setTimeout(r, delay))
    return retryFetch(url, opts, attempt - 1)
  }
  return res
}

10. WebSocket 劫持 -- 校验 Origin

后端

ts 复制代码
import { Elysia } from 'elysia'

new Elysia()
  .ws('/ws', {
    open: (ws) => {
      const origin = ws.data.request.headers.get('origin')
      if (origin !== 'https://yourdomain.com') ws.close()
    }
  })
  .listen(3000)

前端 :正常 new WebSocket('wss://...')

整理一下:10 种攻击与核心防御

攻击 后端核心防御 前端辅助
SQL 注入 参数化查询(? 占位符 + 数组)
XSS 输出转义(escapeHtml textContent
CSRF Bun.CSRF + sameSite:'lax' 自动携带 token
弱密码 Bun.password.hash(Argon2id) 可选强度提示
文件上传 白名单 + 随机名 + 大小限制 accept + 大小预检
路径遍历 resolve + startsWith
中间人攻击 HSTS + 强制 HTTPS 使用 https://
点击劫持 X-Frame-Options: DENY
DDoS / 暴力破解 @elysiajs/rate-limit 指数退避
WebSocket 劫持 校验 Origin

以上 10 个关键词,再开发阶段你可以要求作为提示词给到 AI,帮你写代码实现这些防御措施。

相关推荐
不考研当牛马1 小时前
Django 框架 深度学习 第二课程
后端·python·django
琹箐1 小时前
chrome 插件下载安装;Manifest file is missing or unreadable
前端·chrome
云飞云共享云桌面1 小时前
面向机械研发:双服务器架构搭配云飞云运行 SolidWorks 方案详解
运维·服务器·前端·网络·架构·制造
乐兮创想 小林1 小时前
B2B 内容营销的工程化运营:从内容矩阵建模到 SEO/GEO 联动的完整体系
前端·线性代数·矩阵·网站建设·北京网站建设公司
2501_940041741 小时前
全栈开发提速指南:可以直接用的项目生成提示词
前端·prompt
BomanGe21 小时前
NSK直线导轨LH55EL与NH55EM替代指南
前端·javascript·数据库·经验分享·规格说明书
云水一下1 小时前
Vue.js从零到精通系列(四):前端路由与Vue Router——打造多页单页应用
前端·javascript·vue.js
糯米导航1 小时前
浏览器解析HTML头部的底层逻辑:从字节流到渲染树的关键一步
前端·html
baozj1 小时前
把徒步轨迹做成 3D 地形模型:开源工具「印迹 TrailPrint 3D」
前端·vue.js·github