Mushroom Notes Mushroom Notes
🍄首页
  • JavaSE

    • 基础篇
    • 数据结构
    • IO流
    • Stream流
    • 函数式接口
    • JUC
    • 反射
    • 网络编程
    • 设计模式
  • JavaEE

    • Servlet
    • JDBC
    • 会话技术
    • 过滤器监听器
    • 三层架构
  • JDK

    • 总览
  • JVM

    • 总览
  • 常用mate
  • CSS
  • JavaScript
  • rds 数据库

    • MySQL
    • MySQL 进阶
    • MySQL 库表规范
  • nosql 数据库

    • Redis
    • Redis 进阶
    • Redis 底层
    • MongoDB
  • Spring生态

    • Spring
    • Spring MVC
    • Spring boot
    • Spring Validation
  • Spring Cloud生态

    • Spring Cloud
    • 服务治理
    • 远程调用
    • 网关路由
    • 服务保护
    • 分布式事务
    • 消息中间件
  • 数据库

    • Mybatis
    • Mybatis Plus
    • Elasticsearch
    • Redisson
  • 通信

    • Netty
📚技术
  • 方案专题
  • 算法专题
  • BUG专题
  • 安装专题
  • 网安专题
  • 面试专题
  • 常用网站
  • 后端常用
  • 前端常用
  • 分类
  • 标签
  • 归档

kinoko

一位兴趣使然的热心码农
🍄首页
  • JavaSE

    • 基础篇
    • 数据结构
    • IO流
    • Stream流
    • 函数式接口
    • JUC
    • 反射
    • 网络编程
    • 设计模式
  • JavaEE

    • Servlet
    • JDBC
    • 会话技术
    • 过滤器监听器
    • 三层架构
  • JDK

    • 总览
  • JVM

    • 总览
  • 常用mate
  • CSS
  • JavaScript
  • rds 数据库

    • MySQL
    • MySQL 进阶
    • MySQL 库表规范
  • nosql 数据库

    • Redis
    • Redis 进阶
    • Redis 底层
    • MongoDB
  • Spring生态

    • Spring
    • Spring MVC
    • Spring boot
    • Spring Validation
  • Spring Cloud生态

    • Spring Cloud
    • 服务治理
    • 远程调用
    • 网关路由
    • 服务保护
    • 分布式事务
    • 消息中间件
  • 数据库

    • Mybatis
    • Mybatis Plus
    • Elasticsearch
    • Redisson
  • 通信

    • Netty
📚技术
  • 方案专题
  • 算法专题
  • BUG专题
  • 安装专题
  • 网安专题
  • 面试专题
  • 常用网站
  • 后端常用
  • 前端常用
  • 分类
  • 标签
  • 归档
  • 方案专题

  • 算法专题

  • BUG专题

  • 安装专题

  • 网安专题

    • XSS漏洞
    • CSRF漏洞
    • 后台常见安全漏洞
      • 攻击方式
        • 爆破(暴力破解)
        • 社工(社会工程学)
      • 预防策略
        • 爆破的预防
        • 图形验证码
        • 账号锁定机制
        • 网关限流
      • 预防策略
    • SQL注入漏洞
    • API接口安全性
  • 面试专题

  • 专题
  • 网安专题
kinoko
2023-12-26
目录

后台常见安全漏洞安全

常见漏洞:

  1. 弱口令
  2. 形同虚设的登录
  3. 越权漏洞

# 弱口令


**介绍:**弱口令没有严格和准确的定义,通常认为容易被别人猜测破解的口令均为弱口令。弱口令指的是仅包含
简单数字和字母的口令,例如”123”、”abc”等,因为这样的口令很容易被别人破解。

2022弱指令top10:

提示

password、123456、123456789、guest、qwerty、12345678、111111、col123456、123123

分类:

提示

  • 普通型弱口令就是常见的密码
  • 条件型弱口令就是和用户信息相关的密码,比如生日+手机号、姓名首字母+生日、爱人姓名首字
    母+生日+常用字母(520、1314等)

# 攻击方式


# 爆破(暴力破解)

**概念:**通过爆破工具就可以很容易破解用户的弱口令。暴力破解的原理就是使用用户名和密码字典,一个一个
去枚举尝试是否能够登录。
在理论上来说只要字典足够庞大,枚举总是能够成功的!

爆破工具示例

提示

  • Burp Suite:https://portswigger.net/burp (opens new window)
  • Bruter

# 社工(社会工程学)


**概念:**社工是(社会工程学)简称,一种黑客的攻击手段,通过社会工程的方式获取收集你的相关信息,作为
生成攻击字典的素材。

社会工程的方式很多,如:

提示

  • 网络搜集
  • 社工库
  • 网络钓鱼
  • 使用IM、论坛、邮件、短信等方式接近目标人群以收集更多信息

在互联网上你几乎没有个人隐私!
姓名、生日、邮箱、手机号、某些账号密码都有可能被公开或半公开过。

撞库:某网站A遭到入侵泄露了你部分数据,攻击者可以利用这部分数据对你在网站B的账号发起入侵尝试。

# 预防策略


# 爆破的预防

成因分析:

提示

  1. 密码过于简单
  2. 请求中没有动态参数,都是相对固定内容
  3. 请求可以无限次尝试,没有限制措施

预防策略:

提示

  1. 强制密码复杂度长度、字母大小写数字特殊字符组合、定期修改
  2. 图像验证码双刃剑,太简单了容易辨认也容易被攻击者程序识别,从而失去价值;太复杂模糊了,会增加攻击难度,但同时人眼识别也比较困难,降低用户体验。好在现在有越来越多的验证码方式可供选择,如基于文字语言理解的、基于文字计算的、滑块式的或者识别图像式的等等,比如拼图验证码(网易、极验)、12306的标记图片验证码方式。简单的图形验证码很容易被机器识别(百度提供基于AI的识别接口),复杂的图形验证码也有打码平台人工识别。可以解决请求中没有动态参数,导致攻击者可随意爆破的问题。
  3. 限制重试次数,添加锁定机制根据IP地址、用户名进行尝试次数限制,随着AI的发展对图像验证码识别越来越容易,单靠验证码有时候不能防止爆破,这就需要在服务端,增加更多的安全机制,可以在程序中通过拦截器或者网关做统一的控制。解决攻击者可以无限次尝试的问题,增加攻击难度。

# 图形验证码


验证逻辑

提示

  1. 用户访问登录页面,发起验证码请求
  2. 后端生成验证码图片,并将字符串放入session
  3. 用户输入账密+验证码,点击登录
  4. 后端验证账密及验证码,正确通过,不正确返回登录页面
  5. 删除session

controller示例代码

/**
* 生成验证码
*/
@RequestMapping("/getVerifyCodeImg")
    public void getVerifyCodeImg(HttpServletRequest request, HttpServletResponse response) {
    String code = VerifyCodeUtils.getRandomCodeStr();
    BufferedImage buffImg = VerifyCodeUtils.getImgCode(code);
    logger.debug("Code is {}", code);
    // 将四位数字的验证码保存到Session中。
    HttpSession session = request.getSession();
    session.setAttribute(SESSION_NAME_VERIFY_CODE, code);
    // 禁止图像缓存。
    response.setHeader("Pragma", "no-cache");
    response.setHeader("Cache-Control", "no-cache");
    response.setDateHeader("Expires", 0);
    response.setContentType("image/jpeg");
    // 将图像输出到Servlet输出流中。
    try (ServletOutputStream sos = response.getOutputStream()) {
        ImageIO.write(buffImg, "jpeg", sos);
    } catch (IOException e) {
        logger.error("获取验证码异常", e);
    }
}

/**
* 后台登录提交
*
* @param userName
* @param password
* @param request
* @return
*/
@PostMapping("/login")
public String postLogin(String userName,
                            String password,
                            String verifyCode,
                            HttpServletRequest request,
                            ModelMap map) {
    //第三章增加图形验证码判断
    Object sessionCode =
        request.getSession().getAttribute(SESSION_NAME_VERIFY_CODE);
    verifyCode = verifyCode.toUpperCase();
    if (sessionCode == null || !((String) sessionCode).equals(verifyCode)) {
        //验证不通过
        logger.debug("用户输入的验证码{},session中的验证码{}", verifyCode,
                     sessionCode == null ? "" : sessionCode.toString());
        map.put("result", "登陆失败,请正确输入验证码。");
        return "admin/login";
    } else {
        //Todo 这段代码很关键,没有这段代码的验证码方案1 不能预防爆破,加这段代码
        才可以预防爆破
        request.getSession().removeAttribute(SESSION_NAME_VERIFY_CODE);
        //验证 验证码 通过,进行用户名密码判断校验
        SystemUser systemUser =
            systemUserService.getSystemUserByUserNameAndPwd(userName, password);
        if (systemUser != null) {
            request.getSession().setAttribute("isLogin", true);
            request.getSession().setAttribute("userName", userName);
            request.getSession().setAttribute("user", systemUser);
            //先添加到session,在跳转
            return "redirect:/admin/main";
        } else {
            map.put("result", "登陆失败,检查账号密码是否有误。");
            return "admin/login";
        }
        //增加对象放入session中
        //只是密码的简单判断,哈哈。当然也可以连数据判断
        //if ("admin".equals(userName) && "qweasd".equals(password)) {
        //第二章更新为数据库验证账号密码
        //if (systemUserService.validateLogin(userName, password)) {
        //第三章 更新获取对象,便于根据对象获取id等信息
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

# 账号锁定机制


结合数据库或者redis显示登陆失败的锁定机制,可以使用长期锁定或者临时锁定策略,长期锁定需要管理员手动解锁,临时锁定策略过一定时间自动解除锁定。

  • 临时锁定
  • 长期锁定

下面的示例代码通过一个缓存的Map来实现演示效果,生产环境请按照思路替换为redis或者数据库实
现。

逻辑步骤

提示

  1. 判断账密前先判断账户是否锁定,如果锁定直接返回;
  2. 判断账密后如果账密错误,通过工具类更新登录失败信息;
  3. 判断账密正确,通过工具类清理登录失败信息;
/**
* 这里采用简单的静态Map锁定方案,仅仅用于思路演示
* 生产环境一般使用数据库或者redis实现账号锁定机制
*
*/
public class UserLockUtils {
    static final Logger logger = LogManager.getLogger(UserLockUtils.class);
    public static Map<String, UserLockObject> userLockMap = new HashMap();
    public static int LOCK_FAIL_NUM = 3; //失败锁定的次数
    public static int LOCK_TIME_MINUTE = 30;//30分钟锁定时间
    /**
	* 检查账户是否锁定
	* 达到3次错误尝试后锁定30分钟
	*
	* @param userName
	* @return
	*/
    public static boolean checkLock(String userName) {
        UserLockObject user = userLockMap.get(userName);
        if (user != null) {
            logger.debug("用户{}被锁定,对象信息{}", userName, user);
            int num = user.getFailNum();
            Date date = user.getLastFailTime();
            long timeDifference = ((new Date().getTime() - date.getTime()) / 60 / 1000);
            if (num >= LOCK_FAIL_NUM && timeDifference < LOCK_TIME_MINUTE)
            {
                return true;
            }
        }
        return false;
    }
    /**
	* 账密验证失败后
	* 增加失败记录,失败次数+1,失败时间更新为当前时间
	*
	* @param userName
	*/
    public static void addFailEven(String userName) {
        logger.debug("增加登录失败信息记录{}", userName);
        UserLockObject user = userLockMap.get(userName);
        if (user == null) {
            user = new UserLockObject();
        }
        user.setFailNum(user.getFailNum() + 1);
        user.setLastFailTime(new Date());
        userLockMap.put(userName, user);
    }
    /**
	* 账密验证正常后
	* 清理该用户的失败记录
	*
	* @param userName
	*/
    public static void clearUser(String userName) {
        logger.debug("增加成功,清理{}的登录失败信息", userName);
        userLockMap.remove(userName);
    }


    @Data
    class UserLockObject {
        private int failNum;
        private Date lastFailTime;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@PostMapping("/login")
public String postLogin(String userName, String password, String
                        verifyCode, HttpServletRequest request, ModelMap map) {
    //第三章增加图形验证码判断
    Object sessionCode =
        request.getSession().getAttribute(SESSION_NAME_VERIFY_CODE);
    verifyCode = verifyCode.toUpperCase();
    if (sessionCode == null || !((String)
                                  sessionCode).equals(verifyCode)) {
        //验证不通过
        logger.debug("用户输入的验证码{},session中的验证码{}", verifyCode,
                     sessionCode == null ? "" : sessionCode.toString());
        map.put("result", "登陆失败,请正确输入验证码。");
        return "admin/login";
    } else {
        //验证 验证码 通过,进行用户名密码判断校验
        //这段代码很关键,没有这段代码的验证码方案1 不能预防爆破,加这段代码才可以预
        防爆破
        request.getSession().removeAttribute(SESSION_NAME_VERIFY_CODE);
        //在验证账密前,先判断用户是否锁定
        if (UserLockUtils.checkLock(userName)) {
            map.put("result", "登陆失败,该账户已被锁定。");
            return "admin/login";
        }
        SystemUser systemUser =
            systemUserService.getSystemUserByUserNameAndPwd(userName, password);
        if (systemUser != null) {
            //验证成功,清理锁定信息
            UserLockUtils.clearUser(userName);
            request.getSession().setAttribute("isLogin", true);
            request.getSession().setAttribute("userName", userName);
            //增加对象放入session中
            request.getSession().setAttribute("user", systemUser);
            //先添加到session,在跳转
            return "redirect:/admin/main";
        } else {
            //验证失败,更新锁定信息
            UserLockUtils.addFailEven(userName);
            map.put("result", "登陆失败,检查账号密码是否有误。");
            return "admin/login";
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 网关限流


结合网关实现限流,也可以从一定程度上减少爆破攻击的可能。如:spring cloud gateway

server:
  port: 80
spring:
  cloud:
    gateway:
      routes:
        - id: requestRateLimiter
          uri: http://127.0.0.1:80
      order: 10000
      predicates:
        - Path=/**
      filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1 # 令牌桶的容积
            redis-rate-limiter.burstCapacity: 3 # 流速 每秒
            key-resolver: "#{@hostAddrKeyResolver}" #SPEL表达式对应的bean
application:
  name: gateway-limiter
redis:
  host: 172.17.0.139
  port: 36379
  database: 0
  pass:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

@Component
public class HostAddrKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        System.out.println("限流解析访问的IP地址");
        // 如果一秒内超过三次访问则限制,如返回429状态码
        return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

黑客仍有手段针对ip限流,如采用动态ip,可以基于这个思路采取用户限制等

# 形同虚设的登录


概念:
登录校验不全面,仅针对了某个页面或某个入口,如:只针对了首页做了登录校验,未对新增/删除类接口做身份校验

**预防:**做全局校验或仔细检查项目中的增删改查接口的登录校验

# 越权漏洞


概念:
越权漏洞是一种很常见的逻辑安全漏洞。是由于服务器端对客户提出的数据操作请求过分信任,忽略了
对该用户操作权限的判定,导致修改相关参数就可以拥有了其他账户的增、删、查、改功能,从而导致
越权漏洞。

分类:

提示

  • 水平越权:尝试访问与自己拥有相同权限的用户的资源
  • 垂直越权:低级别攻击者尝试访问高级别用户的资源

原因:

提示

  1. 后台页面未做登录校验或者校验不严谨
  2. 请求接口未做登录校验或者校验不严谨
  3. 对于登录用户未做权限校验(功能权限、操作权限、数据权限)

# 预防策略


提示

  • 使用成熟的权限管理框架如shiro、spring security等
  • 所有后台请求统一拦截,避免遗漏
  • 用户进行访问操作的凭证(如用户ID)优先采用在服务端关联session的方式获取
  • 用户进行访问操作的访问参数(如订单号等)时,采用难以猜测的构造方式,如UUID方式
  • 应对客户端提交的凭证与会话的权限进行严格的验证,如提交的订单号是否为隶属于登录用户
  • 权限不仅仅是菜单的显示与否,更重要的页面的能否访问

# 其他的预防建议


提示

  • 后台入口隐蔽
    • 域名、url、IP限制
    • 后台网址与前台网址要独立
  • 记录操作日志并定期审查日志
  • 定期更换密码
  • 隐藏异常信息
  • html页面源码、JS代码等不要泄露敏感信息
  • 网络传输中明文密码很容易被窃取,一般在传输前先对密码做加密或Hash处理,如页面做md5或
    者App做加密
#安全
上次更新: 2023/12/29 11:32:56
CSRF漏洞
SQL注入漏洞

← CSRF漏洞 SQL注入漏洞→

最近更新
01
JVM 底层
09-13
02
JVM 理论
09-13
03
JVM 应用
09-13
更多文章>
Theme by Vdoing | Copyright © 2022-2024 kinoko | MIT License | 粤ICP备2024165634号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式