JWT Token
- JWT(JSON Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,以JSON对象的形式在各方之间安全地传输信息。
- JWT是一个数字签名,生成的信息是可以验证并被信任的。
- 使用密钥(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对JWT进行签名。
- JWT是目前最流行的跨域认证解决方案
SON Web令牌以紧凑的形式由三部分组成,这些部分由点(.)分隔(Header.Payload.Signature),分别是:
-
Header:base64编码的
json串:{"alg":"HS256","typ":"JWT"}alg: 加密方式type: 令牌类型
-
Payload:base64编码的
json串:{....}以下约定都是非强制性的,一般不建议存放敏感信息
- 注册声明字段:
- iss(JWT的签发者)
- exp(expires,到期时间)
- sub(主题)
- aud(JWT接收者)
- iat(issued at,签发时间)
- …
- 公开声明:公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的
- 私有声明:私有声明是提供者和消费者所共同定义的声明
- 注册声明字段:
-
Signature:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
HTTP1/1.1/2.0/3.0
网络安全
XSS(跨站脚本攻击)
攻击者脚本 嵌入 被攻击网站,获取用户cookie等隐私信息。
原因:
- 将不可信的字符串当作html片段输出
- innerHTML
- document.write
- …
- href属性
<a href="USER_INPUT">Link</a><!-- 攻击:USER_INPUT = javascript:alert(document.cookie) -->- 直接拼接html字符串
<!-- 危险 --><input value=USER_INPUT><!-- 攻击:USER_INPUT = " onfocus="alert(1)" autofocus=" -->防范:
- 输出编码(Output Encoding)
- HTML 上下文:
<→< - JS 上下文:使用
JSON.stringify()而非拼接
- HTML 上下文:
- CSP(Content Security Policy)
Content-Security-Policy: default-src 'self'; script-src 'nonce-xxx’
- 设置 Cookie 的
HttpOnly(防 JS 窃取) - 避免直接使用
innerHTML/eval()/document.write()
XSS攻击可以分为3类:存储型(持久型)、反射型(非持久型)、基于DOM。
- 存储型:数据在上传到服务器时未做转义处理,在H5中也未转义就输出(innertHTMl\href等)。
- 反射型:直接从用户端获取的输入(地址了、用户输入内容)未转义,就输出。
- 基于DOM:直接修改HTML内容,注入恶意脚本
前两个对内容进行转义后保存或输出即可。最后一个则需要通过CSP协议来避免浏览器侧自动加载不可信来源的脚本、请求、图片等
CSRF(跨站请求伪造
用户已登录 bank.com,同时访问了恶意网站 evil.com。
evil.com 诱导浏览器向 bank.com/transfer 发起请求(如自动提交表单),浏览器自动带上 bank.com 的 Cookie,服务器误以为是用户自愿操作。
⚠️ 关键:浏览器同源策略不阻止“发送请求”,只阻止“读取响应”。
解决方案:
| Anti-CSRF Token(最有效) | 表单/请求头中加入随机 token,服务端校验 |
|---|---|
| SameSite Cookie 属性 | Set-Cookie: session=xxx; SameSite=Lax(推荐) |
请求来源:检查 Origin / Referer 头 | 拒绝非同源请求(但可被伪造或缺失) |
| 敏感操作二次验证 | 如短信验证码、密码确认 |
攻击方式:
- 通过
<img src='恶意链接' />发起get请求 - 通过
<form>表单发起post请求
<form id= 'hacker-form' action="https://time.geekbang.org/sendcoin" method=POST> <input type="hidden" name="userll" value="hacker" /> <input type="hidden" name="numberll" value="100" /></form><script> document.getElementById ('hacker-form').submit(); </script>- 引诱用户点击链接:
<a href="[https://](https://time.geekbang.org/sendcoin?user=hacker&number=100)xxxx" taget="xxx" >领取福利</a>
iframe
攻击方式:
-
嵌入的
iframe被劫持或出现问题解决:为 **
iframe设置sandbox属性,通过它可以对iframe**的行为进行各种限制,充分实现“最小权限“原则 默认情况下,如果只写<iframe sandbox src="...">,则会启用所有限制allow-same-origin允许内容保留其真实来源(而非被视作唯一源),可访问 cookies、IndexedDB 等 allow-scripts允许执行 JavaScript allow-forms允许提交表单 allow-popups允许打开新窗口/标签页(如 window.open())allow-top-navigation允许 iframe 导航顶层页面(危险!慎用) allow-top-navigation-by-user-activation仅在用户交互(如点击)后允许导航顶层页面 allow-downloads允许触发下载(如 a[download]或Blob下载)allow-modals允许使用 alert(),confirm()等模态对话框allow-pointer-lock允许使用 Pointer Lock API allow-orientation-lock允许锁定屏幕方向 allow-presentation允许使用 Presentation API allow-popups-to-escape-sandbox允许弹出窗口不受沙箱限制(例如新窗口可运行脚本) -
点击劫持,外部网页通过
iframe嵌入被攻击的网页,通过修改样式效果诱导用户点击。解决:
- 设置响应头:
X-Frame-Options
X-Frame-Options是一个 HTTP 响应头,用于控制当前页面是否可以被嵌入到<frame>、<iframe>、<embed>或<object>中,从而防止 点击劫持(Clickjacking)值 含义 兼容性 DENY页面不能在任何 frame/iframe 中显示 所有现代浏览器支持 SAMEORIGIN页面只能在同源的 frame/iframe 中显示 所有现代浏览器支持 ALLOW-FROM uri页面可以在指定来源的 frame 中显示 ❌ 已被废弃,多数浏览器不支持 - 更现代的替代方案:
Content-Security-Policy: frame-ancestors,优先级高于X-Frame-Options
例如:
Content-Security-Policy: frame-ancestors 'self';frame-ancestors含义 是否允许嵌套 示例场景 'none'禁止任何页面将当前页面嵌入 <iframe>、<frame>等❌ 完全禁止 敏感页面(如银行登录页) 'self'仅允许同源页面嵌套(协议 + 域名 + 端口一致) ✅ 仅同源 同站内嵌管理面板 https://trusted.example.com仅允许指定来源嵌套(必须是完整 URI,含协议) ✅ 仅该域名 第三方合作站点嵌入小部件 https://*.example.com允许 example.com 的所有子域嵌套 ✅ 所有子域 多租户 SaaS 平台 'self' https://partner.com允许多个来源:同源 + 指定外部域名 ✅ 同源或 partner.com 内部系统 + 外部合作伙伴 *允许任意来源嵌套(⚠️ 极度危险) ✅ 任意网站 不推荐使用(易遭点击劫持) (未设置 frame-ancestors)默认行为:若设置了其他 CSP 指令,则默认为 *;但若同时存在X-Frame-Options,则由其控制取决于浏览器和其它头 不安全,应显式设置 - 设置响应头:
SQL注入
来自用户的输入、其他前端的数据输入的数据直接参与后端的数据库查询时的SQL语句拼接时。
例如下面的SQL语句拼接:
"SELECT * FROM users WHERE username = '"+ userName + "' and password = '" + psw + "'"若userName为admin'—
SELECT * FROM users WHERE username = 'admin'--' AND password = 'anything';预防:
- 前端:
- 校验不允许输出特殊字符串与引号等
- 对输入内容进行转义
- 后端:
- 避免使用字符串拼接的方式生成SQL语句,改用
?占位符编译的方式、或者对不可信来源的内容进行转义 - 避免将SQL错误消息直接返回给前端(会帮助入侵者分析)
- 避免使用字符串拼接的方式生成SQL语句,改用
OS命令劫持
OS命令注⼊和SQL注⼊差不多,只不过SQL注⼊是针对数据库的,⽽OS命令注⼊是针对操作系统的。
例如的nodejs的服务中,会根据前端的提交的表单内容克隆特定的仓库:
exec(`git clone ${params.repo} /some/path`);若params.repo 为[https://github.com/xx/xx.git](https://github.com/xx/xx.git) && rm -rf /* &&
则命令就会变为:
exec(`git clone https://github.com/xx/xx.git && rm -rf /* && /some/path`);正确的做法:
const repo = encode(params.repo) // 对 repo 中的 " 转义exec(`git clone "${repo}" /some/path`);