This commit is contained in:
shengzhang
2021-04-23 19:46:37 +08:00
parent 9a2e14d147
commit 79d7967e0d
35 changed files with 516 additions and 196 deletions

View File

@@ -45,6 +45,7 @@
- [Session模型详解](/fun/session-model)
- [TokenInfo参数详解](/fun/token-info)
- [框架源码所有技术栈](/fun/tech-stack)
- [Web开发常见漏洞防护](/fun/web-loophole)
<!-- - [Sa-Token大事记](/fun/timeline) -->

View File

@@ -0,0 +1,112 @@
# Web开发常见漏洞防护
本章介绍web开发时常见漏洞的防护方法
### 点击劫持
简而言之,点击劫持就是攻击者会自己搭建一个网页,这个网页分为两层:
- 上层是被iframe导入的被攻击网站具有一些敏感性操作比如转账、点赞等按钮这一层会完全透明
- 下层是攻击者自己精心制作的网页,它会准备一个按钮诱导你进行点击(比如点击领取红包等),当你点击这个按钮时,响应你的将不会是这个按钮,而是上层的转账页面,在不知情的情况下造成财产损失
详情介绍参考:[https://blog.csdn.net/qq_32523587/article/details/79613768](https://blog.csdn.net/qq_32523587/article/details/79613768)
防范点击劫持的最有效做法就是增加响应头:`X-Frame-Options: DENY`, 告诉浏览器我们的网站不可以通过 iframe 进行展示(浏览器收到此响应头的指示之后,会拒绝渲染页面),
从根本上杜绝了点击劫持发生的可能,在 [全局过滤器](/use/global-filter) 章节的示例中,我们已经展示了如何在过滤器中增加安全响应头
响应头`X-Frame-Options`有三个取值:
- `DENY`: 任何时候都不可以通过 iframe 展示视图
- `SAMEORIGIN`: 在同域下可以通过 iframe 展示视图
- `ALLOW-FROM uri`: 指定地址来源的访问下可以通过 iframe 展示视图
除了后端的响应头,我们还可以在前端使用如下方式进行判断:
``` js
// 判断当前页面是否在顶层视口打开
if(top != window) {
// 跳入一个安全页面比如404页
location.href="xxx";
}
```
除了跳转页面你还可以用其它方法防御点击劫持比如加载一个全局遮罩来隔离用户的点击操作或者在非顶层窗口下拒绝提交token使用户保持未登录状态
### XSS攻击
XSS跨站脚本攻击就是指攻击者在一段正常的内容中嵌入恶意脚本使得访问网页的用户自动运行一些破坏性的代码
例如一个论坛具有发帖功能,攻击者在发帖时故意插入一段如下内容:
``` java
<img src="xxx" onerror="alert('xss攻击')" />
```
如果论坛服务端没有对此进行任何防护,那么用户每次访问这个帖子的时候都会被强制弹窗,
事实上真正的`XSS攻击`绝不只是弹窗骚扰一下那么简单它可以完成窃取Cookie自动转账等破坏性操作
防范XSS攻击
1. 首先安全响应头给安排上:`X-Frame-Options: 1; mode=block`, 这是浏览器默认提供的XSS防护机制
2. 有条件的情况下尽量使用前后台分离架构传统服务端渲染视图时几乎每一个变量都可能成为XSS注入点而前后台分离下一般只有富文本渲染才会有机会XSS注入
3. 对所有的用户输入必须XSS过滤特别是字符串型参数
4. 可以使用一些自动扫描工具寻找潜在的 XSS 漏洞
### CSRF攻击
CSRF跨站请求伪造又称 XSRF攻击流程如下
1. 用户登陆站点`a.com`身份令牌被写入Cookie中
2. 攻击者搭建站点`b.com`,引诱用户访问
3. 用户访问`b.com`时自动执行了攻击者准备的js代码调用`a.com`的转账接口
4. 用户在不知情的情况下,造成了财产损失
仅仅访问一个不安全的站点就让我们造成了财产损失事实上真正的CSRF攻击并没有这么简单挡在攻击者第一道门槛便是`CORS同源策略`
同源策略限制了js在`b.com`中只能操作`b.com`的数据(`Cookie`、`localStorage`、`DOM`等),而无法直接操作`a.com`的数据。
这就导致一个结果:虽然在`b.com`可以调用`a.com`的转账接口,但是却无法携带用户储存在`a.com`的授权Cookie对于`a.com`来讲,即使收到了浏览器发来的请求,
也因为请求中没有携带token令牌而无法识别调用者具体是谁只能将其视为一次无效调用。
但是,请注意!这个小小的限制,虽然为用户提供了安全保护,却也为我们开发者造成了不小的困扰,特别是在前后端分离架构下,我们经常会遇到这个错误:
![https://oss.dev33.cn/sa-token/doc/kuayu.png](https://oss.dev33.cn/sa-token/doc/kuayu.png)
这就是导致无数前端后端互相撕逼的 —— 跨域!
浏览器在检测到你身处`b.com`却想要调用`a.com`的接口时,会率先发送一个`OPTIONS`预检请求,目的是为了询问`a.com`是否同意`b.com`发起的请求,
在默认情况下,`a.com`收到一个陌生的第三方网站发来的请求,做出的回应肯定是:`不允许`, 浏览器收到回应就识相的关闭了请求,跨域请求失败
但是,有些开发者为了省事,直接设置了响应头: `Access-Control-Allow-Origin: *`,允许任何第三方网站的请求,这就给`CSRF攻击`留下了可乘之机
假设我们设置了只允许指定的网站跨域请求就万事大吉了吗并没有攻击者仍可以通过抓包等手段得到我们的转账url
在`b.com`里,通过`open(url)`直接打开一个新的窗口调用转账接口,由于是属于打开新页面,浏览器连`OPTIONS`预检请求都不会发送,而是直接调用接口成功
此招无解吗?并不。由于它是属于打开新页面,这就导致调用接口时只能发送`get请求`,我们在设计接口时只需要遵守一个准则:`敏感接口一律post禁止get调用`即可。
究其原因,导致`CSRF攻击`频频发生的原因是什么?是我们在跨域请求时,浏览器总是“自作聪明”的自动提交主站`Cookie`
在浏览器的不断更新中Cookie的跨域规则变得愈发复杂新手开发者及其容易绕的晕头转向而同时`w3c`对`Cookie`规范的各种修修补补又总是解决一个问题的同时暴露出其他的N多问题
既然Cookie机制如此难以驾驭我们何不果断的放弃Cookie机制改用`localStorage`机制存储会话token这种方式轻松避免了`自动提交`带来的各种安全问题。
事实上,`localStorage存储` + `header请求头提交`也是前后台分离趋势下的常见会话处理方案
篇幅有限,我们总结一下防范`CSRF攻击`要点
**在Cookie模式下**
1. 仅靠`CORS同源策略`无法彻底防范`CSRF攻击`,我们必须在后台建立`第三方域名白名单`,只有在白名单中的第三方域名才可以跨域调用我们的接口
2. 涉及到数据增删改类型的接口,必须是`post`模式(或其它),严禁`get`模式,查询接口可以`get`
3. 敏感操作增加验证码或者二次验证密码,减小被攻击的概率
**在 localStorage存储 + header请求头提交 模式下**
1. 在配置文件中,配置`is-read-cookie: false`关闭Cookie模式防止Sa-Token在登录时注入Cookie
2. 同上,敏感操作增加验证码或者二次验证密码,减小被攻击的概率
有关CSRF攻防讲解的比较通透的一篇文章[https://juejin.cn/post/6844903689702866952](https://juejin.cn/post/6844903689702866952)
### Token泄露
Token泄露一般发生在客户端比如用户连接了不安全的WiFi导致通讯被监听虽然此情形下token泄露的责任在于用户但是我们还是有必要采取一定的措施使其损失降到最低
1. 有条件上https的话一律https
2. token有效期一定不能设置为永久而且要尽量的短but为了不影响用户体验又不能设置特别的短so: 7-30天是个比较合适的范围
3. 对敏感操作接口,增加密码二次校验(或手机验证码等)
4. 用户更改密码后使其历史会话直接过期
5. 有条件的情况下后台管理增加踢人下线功能对已经泄露token的账号可以及时清理下线
<br><br>
更多类型漏洞连载中.... 欢迎提交pr

View File

@@ -15,7 +15,7 @@
<a href="/">
<div class="logo-box">
<img src="logo.png" title="logo" />
<h1 class="logo-text">sa-token</h1>
<h1 class="logo-text">Sa-Token</h1>
</div>
</a>
<nav>
@@ -47,7 +47,7 @@
</div>
<script>
var name = '<img style="width: 60px; height: 60px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
name += '<b style="font-size: 28px; vertical-align: middle;">sa-token</b> <sub>v1.17.0</sub>'
name += '<b style="font-size: 28px; vertical-align: middle;">Sa-Token</b> <sub>v1.17.0</sub>'
window.$docsify = {
name: name, // 名字
repo: 'https://github.com/dromara/sa-token', // github地址

View File

@@ -82,7 +82,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
}
/* 代码行号盒子样式 */
.code-line-box {list-style-type: none; border-right: 1px solid #000; position: absolute; top: 0; left: 0; width: 40px;}
.code-line-box {list-style-type: none; border-right: 1px solid #000; position: absolute; top: 0; left: 0; width: 40px; user-select: none;}
.code-line-box {padding: calc(1.5em + 1px) 0px !important; padding-bottom: calc(1.5em + 20px) !important; margin: 0px !important;}
.code-line-box {line-height: inherit !important; background-color: #111; color: #aaa;font-weight: 400;font-size: 0.85em;text-align: center;}
.code-line-box {font-family: source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace;}

View File

@@ -7,6 +7,11 @@
<table class="gzh-table" style="text-align: center;">
<tr>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzA4MDMyODg4OQ==&mid=2649482871&idx=2&sn=b376585faaf814d9072af539efda68fe&send_time="/>
<b>大侠学JAVA</b>
<span>道阻且长行则将至专注分享JAVA领域的干货</span>
</td>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=Mzg2MDIxNjAzNg==&mid=2247485810&idx=1&sn=afd46d5924afbc1030a87b5d56265fdf&send_time="/>
<b>Java大厂面试官</b>
@@ -19,7 +24,6 @@
</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>

View File

@@ -1,7 +1,7 @@
# Spring WebFlux 集成 Sa-Token 示例
WebFlux基于Reactor响应式模型开发有着与标准ServletAPI完全不同的底层架构因此要适配WebFlux, 必须提供与Reactor相关的整合实现
本篇将以WebFlux为例展示sa-token与Reactor响应式模型web框架相整合的示例, **你可以用同样方式去对接其它Reactor模型Web框架**
本篇将以WebFlux为例展示sa-token与Reactor响应式模型web框架相整合的示例, **你可以用同样方式去对接其它Reactor模型Web框架**(Netty、Soul、Gateway等)
整合示例在官方仓库的`/sa-token-demo-webflux`文件夹下,如遇到难点可结合源码进行测试学习

View File

@@ -35,13 +35,10 @@ public class SaTokenConfigure {
public SaServletFilter getSaReactorFilter() {
return new SaServletFilter()
// 指定 [拦截路由]
.addInclude("/**")
// 指定 拦截路由 与 放行路由
.addInclude("/**").addExclude("/favicon.ico")
// 指定 [放行路由]
.addExclude("/favicon.ico")
// 指定[认证函数]: 每次请求执行
// 认证函数: 每次请求执行
.setAuth(r -> {
System.out.println("---------- 进入sa-token全局认证 -----------");
@@ -51,11 +48,26 @@ public class SaTokenConfigure {
// 更多拦截处理方式,请参考“路由拦截式鉴权”章节
})
// 指定[异常处理函数]:每次[认证函数]发生异常时执行此函数
// 异常处理函数:每次认证函数发生异常时执行此函数
.setError(e -> {
System.out.println("---------- 进入sa-token异常处理 -----------");
return AjaxJson.getError(e.getMessage());
})
// 前置函数:在每次认证函数之前执行
.setBeforeAuth(r -> {
// ---------- 设置一些安全响应头 ----------
SaHolder.getResponse()
// 服务器名称
.setServer("sa-server")
// 是否可以在iframe显示视图 DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
.setHeader("X-Frame-Options", "SAMEORIGIN")
// 是否启用浏览器默认XSS防护 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时停止渲染页面
.setHeader("X-Frame-Options", "1; mode=block")
// 禁用浏览器内容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
;
})
;
}

View File

@@ -117,6 +117,29 @@ StpUtil.checkRoleOr("super-admin", "shop-admin");
你可以创建一个全局异常拦截器,统一返回给前端的格式,参考:[码云GlobalException.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java)
### 权限通配符
Sa-Token允许你根据通配符指定泛权限例如当一个账号拥有`user*`的权限时,`user-add`、`user-delete`、`user-update`都将匹配通过
``` java
// 当拥有 user* 权限时
StpUtil.hasPermission("user-add"); // true
StpUtil.hasPermission("user-update"); // true
StpUtil.hasPermission("art-add"); // false
// 当拥有 *-delete 权限时
StpUtil.hasPermission("user-add"); // false
StpUtil.hasPermission("user-delete"); // true
StpUtil.hasPermission("art-delete"); // true
// 当拥有 *.js 权限时
StpUtil.hasPermission("index.js"); // true
StpUtil.hasPermission("index.css"); // false
StpUtil.hasPermission("index.html"); // false
```
上帝权限:当一个账号拥有 `"*"` 权限时,他可以验证通过任何权限码 (角色认证同理)
### 如何把权限精确搭到按钮级?
权限精确到按钮级的意思就是指:**权限范围可以控制到页面上的每一个按钮是否显示**