fix:bug
This commit is contained in:
24
Readme.md
24
Readme.md
@@ -2,55 +2,55 @@
|
|||||||
|
|
||||||
## 常见漏洞及解决方案
|
## 常见漏洞及解决方案
|
||||||
|
|
||||||
1. sql 注入
|
- sql 注入
|
||||||
|
|
||||||
解决方案:参数检测,拦截非法入参,后端使用druid 连接池的sql防火墙
|
解决方案:参数检测,拦截非法入参,后端使用druid 连接池的sql防火墙
|
||||||
参见:com.taoyuanx.securitydemo.web
|
参见:com.taoyuanx.securitydemo.web
|
||||||
|
|
||||||
2. xss攻击
|
- xss攻击
|
||||||
|
|
||||||
解决方案:参数检测,拦截非法入参,转义html字符,参见com.taoyuanx.securitydemo.web
|
解决方案:参数检测,拦截非法入参,转义html字符,参见com.taoyuanx.securitydemo.web
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3. 跨站请求
|
- 跨站请求
|
||||||
|
|
||||||
解决方案:设置允许跨站的header信息
|
解决方案:设置允许跨站的header信息
|
||||||
|
|
||||||
4. 文件,图片等非站内请求
|
- 文件,图片等非站内请求
|
||||||
|
|
||||||
解决方案:防盗链处理(Http Rerfer头部,nginx可设置)
|
解决方案:防盗链处理(Http Rerfer头部,nginx可设置)
|
||||||
|
|
||||||
5. 接口暴力访问
|
- 接口暴力访问
|
||||||
|
|
||||||
解决方案:系统限流,全局限流,单个ip限流,黑名单等,参见:com.taoyuanx.securitydemo.security.RateLimitAspect,com.taoyuanx.securitydemo.web.BlackListFilter
|
解决方案:系统限流,全局限流,单个ip限流,黑名单等,参见:com.taoyuanx.securitydemo.security.RateLimitAspect,com.taoyuanx.securitydemo.web.BlackListFilter
|
||||||
|
|
||||||
7. 文件未授权访问
|
- 文件未授权访问
|
||||||
|
|
||||||
解决方案:上传的文件,展示时后端返回签名的文件,访问时,走一次后端,方便做权限验证,参见,/api/upload,/api/file
|
解决方案:上传的文件,展示时后端返回签名的文件,访问时,走一次后端,方便做权限验证,参见,/api/upload,/api/file
|
||||||
文件存储时,去除可执行权限,尽量和应用服务器进行物理隔离
|
文件存储时,去除可执行权限,尽量和应用服务器进行物理隔离
|
||||||
|
|
||||||
8. 文件不安全类型上传
|
- 文件不安全类型上传
|
||||||
|
|
||||||
解决方案:校验文件类型,校验流信息,校验文件真实类型,参见/api/upload
|
解决方案:校验文件类型,校验流信息,校验文件真实类型,参见/api/upload
|
||||||
|
|
||||||
9. 密码泄露风险
|
- 密码泄露风险
|
||||||
|
|
||||||
密码加密传输,参见login.html
|
密码加密传输,参见login.html
|
||||||
|
|
||||||
10. 越权访问
|
- 越权访问
|
||||||
|
|
||||||
解决方案:权限控制,参见SimpleAuthHandlerIntercepter
|
解决方案:权限控制,参见SimpleAuthHandlerIntercepter
|
||||||
如果通过tomcat发布静态文件,可通过过滤器禁止非授权访问,如采用其他静态资源服务器,可严格控制后台权限,保证数据不被越权访问
|
如果通过tomcat发布静态文件,可通过过滤器禁止非授权访问,如采用其他静态资源服务器,可严格控制后台权限,保证数据不被越权访问
|
||||||
,静态资源越权访问,可通过client端js控制location
|
,静态资源越权访问,可通过client端js控制location
|
||||||
|
|
||||||
11. 中间人攻击
|
- 中间人攻击
|
||||||
|
|
||||||
解决方案:采用https协议,参数签名,返回值签名,防止参数或返回值被篡改
|
解决方案:采用https协议,参数签名,返回值签名,防止参数或返回值被篡改
|
||||||
|
|
||||||
12. slowhttp 攻击
|
- slowhttp 攻击
|
||||||
|
|
||||||
解决方案:限制恶意访问,有钱的买防护工具,(阿里云盾,知道创宇等),没钱的多部署几台机器,修改连接超时时间,事后分析ip,封禁
|
解决方案:限制恶意访问,有钱的买防护工具,(阿里云盾,知道创宇等),没钱的多部署几台机器,修改连接超时时间,事后分析非法ip封禁,
|
||||||
协议漏洞,没啥好防护的策略,没钱的事后防范吧
|
协议漏洞,没啥好防护的策略,没钱的事后防范吧
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
7
pom.xml
7
pom.xml
@@ -6,13 +6,12 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>2.1.7.RELEASE</version>
|
<version>2.1.7.RELEASE</version>
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.taoyuanx</groupId>
|
<groupId>com.taoyuanx</groupId>
|
||||||
<artifactId>security-demo</artifactId>
|
<artifactId>javaweb_security_handle</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>security-demo</name>
|
<name>javaweb_security_handle</name>
|
||||||
<description>java security demo</description>
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.taoyuanx.securitydemo.config;
|
package com.taoyuanx.securitydemo.config;
|
||||||
|
|
||||||
import com.taoyuanx.securitydemo.security.ratelimit.AbstractRateLimiter;
|
import com.taoyuanx.securitydemo.security.ratelimit.AbstractRateLimiter;
|
||||||
|
import com.taoyuanx.securitydemo.security.ratelimit.GuavaRateLimiter;
|
||||||
import com.taoyuanx.securitydemo.security.ratelimit.RedisRateLimiter;
|
import com.taoyuanx.securitydemo.security.ratelimit.RedisRateLimiter;
|
||||||
import com.taoyuanx.securitydemo.utils.RSAUtil;
|
import com.taoyuanx.securitydemo.utils.RSAUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -62,13 +63,18 @@ public class GlobalConfig implements InitializingBean {
|
|||||||
* @param redisTemplate
|
* @param redisTemplate
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Bean
|
/* @Bean
|
||||||
@Autowired
|
@Autowired
|
||||||
public AbstractRateLimiter rateLimiter(StringRedisTemplate redisTemplate) {
|
public AbstractRateLimiter redisRateLimiter(StringRedisTemplate redisTemplate) {
|
||||||
RedisRateLimiter redisRateLimiter = new RedisRateLimiter(redisTemplate);
|
RedisRateLimiter redisRateLimiter = new RedisRateLimiter(redisTemplate);
|
||||||
return redisRateLimiter;
|
return redisRateLimiter;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AbstractRateLimiter guavaRateLimiter() {
|
||||||
|
GuavaRateLimiter guavaRateLimiter = new GuavaRateLimiter();
|
||||||
|
return guavaRateLimiter;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
|||||||
@@ -158,11 +158,7 @@ public class BussinessController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录安全控制
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@PostMapping("loginOut")
|
@PostMapping("loginOut")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public void loginOut(HttpServletResponse response, HttpServletRequest request) throws Exception {
|
public void loginOut(HttpServletResponse response, HttpServletRequest request) throws Exception {
|
||||||
@@ -171,7 +167,7 @@ public class BussinessController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 黑名单测试
|
* 文件上传
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -206,9 +202,11 @@ public class BussinessController {
|
|||||||
public void upload(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
public void upload(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||||
fileHandler.handleFile(response, request);
|
fileHandler.handleFile(response, request);
|
||||||
}
|
}
|
||||||
@RateLimit(type = RateLimitType.TOTAL_COUNT,key = "rate_count",totalCount = 100)
|
@RateLimit(type = RateLimitType.TOTAL_COUNT,key = "rate_count",totalCount = 10)
|
||||||
@GetMapping("rate_count")
|
@GetMapping("rate_count")
|
||||||
public void rateCount(int index) throws Exception {
|
@ResponseBody
|
||||||
System.out.println("rate_count\t"+index);
|
public Result rateCount() throws Exception {
|
||||||
|
System.out.println("rate_count\t");
|
||||||
|
return ResultBuilder.success("ok");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class TokenAuthHandlerIntercepter implements HandlerInterceptor {
|
|||||||
}
|
}
|
||||||
Map<String, Object> tokenData = toeknHelper.vafy(token);
|
Map<String, Object> tokenData = toeknHelper.vafy(token);
|
||||||
Long tokenAccountId = toeknHelper.getAccountId(tokenData);
|
Long tokenAccountId = toeknHelper.getAccountId(tokenData);
|
||||||
if (tokenAccountId != accountId) {
|
if (!tokenAccountId.equals(accountId) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package com.taoyuanx.securitydemo.security.ratelimit;
|
|||||||
* @author dushitaoyuan
|
* @author dushitaoyuan
|
||||||
* @desc 抽象限流
|
* @desc 抽象限流
|
||||||
* @date 2019/9/5
|
* @date 2019/9/5
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractRateLimiter {
|
public abstract class AbstractRateLimiter {
|
||||||
|
|
||||||
@@ -20,16 +19,23 @@ public abstract class AbstractRateLimiter {
|
|||||||
return doTryAcquire(1, key, limit);
|
return doTryAcquire(1, key, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param permits 申请令牌数量
|
||||||
|
* @param key 限流标识
|
||||||
|
* @param limit 速率
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public abstract boolean doTryAcquire(int permits, String key, Double limit);
|
public abstract boolean doTryAcquire(int permits, String key, Double limit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加资源访问次数 用户可自行持久化记录
|
* 增加资源访问次数 用户可自行持久化记录
|
||||||
* @param count
|
* @param count (申请资源数量)
|
||||||
* @param key
|
* @param key (资源key)
|
||||||
* @param totalCount
|
* @param totalCount (资源总量)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract boolean tryCount(int count, String key, Long totalCount);
|
public abstract boolean tryCount(int count, String key, Long totalCount);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ public class GuavaRateLimiter extends AbstractRateLimiter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryCount(int count, String key, Long totalCount) {
|
public boolean tryCount(int count, String key, Long totalCount) {
|
||||||
|
if (count > totalCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
//标记后,直接返回false
|
//标记后,直接返回false
|
||||||
if (TOTAL_LIMIT_ZERO_FLAG.mightContain(key)) {
|
if (TOTAL_LIMIT_ZERO_FLAG.mightContain(key)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -53,18 +56,15 @@ public class GuavaRateLimiter extends AbstractRateLimiter {
|
|||||||
LongAdder longAdder = null;
|
LongAdder longAdder = null;
|
||||||
if (countHolder.containsKey(key)) {
|
if (countHolder.containsKey(key)) {
|
||||||
longAdder = countHolder.get(key);
|
longAdder = countHolder.get(key);
|
||||||
longAdder.add(-count);
|
if (longAdder.longValue() >=totalCount) {
|
||||||
//资源总数用完后,标记
|
|
||||||
if (longAdder.longValue() <= 0) {
|
|
||||||
TOTAL_LIMIT_ZERO_FLAG.put(key);
|
TOTAL_LIMIT_ZERO_FLAG.put(key);
|
||||||
countHolder.remove(key);
|
countHolder.remove(key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
longAdder.add(count);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (count > totalCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
longAdder = new LongAdder();
|
longAdder = new LongAdder();
|
||||||
countHolder.putIfAbsent(key, longAdder);
|
countHolder.putIfAbsent(key, longAdder);
|
||||||
countHolder.get(key).add(count);
|
countHolder.get(key).add(count);
|
||||||
|
|||||||
@@ -1,17 +1,3 @@
|
|||||||
|
|
||||||
#数据库连接池
|
|
||||||
#spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
|
|
||||||
#spring.datasource.username:root
|
|
||||||
#spring.datasource.password:root
|
|
||||||
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
|
|
||||||
#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
|
|
||||||
#spring.datasource.initialSize=10
|
|
||||||
#spring.datasource.minIdle=10
|
|
||||||
#spring.datasource.maxActive=100
|
|
||||||
#spring.datasource.maxWait=60000
|
|
||||||
#spring.datasource.timeBetweenEvictionRunsMillis=60000
|
|
||||||
#spring.datasource.filters=wall
|
|
||||||
|
|
||||||
spring.profiles.active=@profiles.active@
|
spring.profiles.active=@profiles.active@
|
||||||
|
|
||||||
spring.redis.database=2
|
spring.redis.database=2
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class SecurityDemoApplicationTests {
|
|||||||
public void reateLimitCount() throws Exception {
|
public void reateLimitCount() throws Exception {
|
||||||
int batch=101;
|
int batch=101;
|
||||||
for(int i=0;i<batch;i++){
|
for(int i=0;i<batch;i++){
|
||||||
bussinessController.rateCount(i);
|
bussinessController.rateCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user