代码审计之越权漏洞
友情提示:本文有点繁琐,我试图写的比较好但是不尽人意
从代码角度讲述「权限校验」以及「越权漏洞怎么查找预防」。(以「java」语言为主)
权限漏洞的意义在于「使用敏感功能」或者看见了「其他人敏感信息」。敏感信息泄露某种程度也是非常大的安全隐患。
越权种类:「未授权 水平越权 垂直越权」
「未授权」:不需要身份认证就使用系统功能接口
「水平越权」:查看和自己同级权限的其他人的信息
「垂直越权」:一般强调的是低权限用户使用了高权限用户的功能
java语言是一个相对而言比较严谨的语言,极其喜欢条条框框把程序员行为控制的死死的。
所以权限问题也不例外。
javaweb框架里就有好几种权限控制框架比如「shiro」,「springsecurity」,「Sa-Token」。
一般企业java代码里上述三种权限控制框架都是常见的,也有自己二次封装内部使用的闭源的其他权限控制结构。
除去权限控制框架,也有直接在过滤器,拦截器里做权限校验的。
对于在企业工作的代码审计人员在审计权限漏洞时对上述提到的框架还有过滤器,拦截器都是要着重看。
对于野生的开源的javaweb项目来说也有纯纯的不使用任何框架,也不在过滤器拦截器里写身份校验权限校验。这种对于审计人员来说简直噩梦。
我首先拿这种既不使用权限框架也不使用过滤器拦截器的项目作为代码举例
这种项目本身是怎么做身份校验权限校验呢。
最原始手段,「session+cookie」, 用户登录成功以后,服务器自己会生成一份session值代表用户身份信息,并且在内存/数据库里保存。然后通过响应头的形式,向客户端发送一个身份认证的Cookie(存储session的id),客户端会自动将Cookie保存在浏览器中。随后,当客户端每次请求服务器的时候,浏览器会自动将身份认证相关的Cookie,通过请求头的形式发送给服务器,服务器再拿请求头中的cookie里的JSESSIONID值去找到对应的内存/数据库的对应的用户信息。一般来说sessionid难以伪造。
如下图,这是我登录成功以后,cookie里保存的JSESSIONID
从代码角度来说服务端进行用户身份验证主要是通过「session.getAttribute」函数:
从请求中session里获取userId然后通过userId去数据库找到对应user资源再把查询的结果返回前端
每次请求某个接口资源都要首先取出Session里userId再去数据库对比找到对应的user资源信息。是非常繁琐的。
权限:用户身份认证,资源访问权限。资源访问权限有的是来自用户身份认证以后比如上述代码找到userId以后再去数据库找到对应用户的资源,也有下面这种不与用户身份绑定的。
比如下面资源id rcid就是直接取值前端传来的,有篡改风险。所以此处存在越权。
即「usrId(用户标识)」或者「资源Id」不是来自Session里,直接来自用户前端输入的数据,那么一般来说可能被篡改有越权风险。看取值方式以及接口管理
一个项目大大小小接口那么多 每个都去检查看太麻烦了。
于是发明了权限校验框架。「权限校验框架」主要是通过「特定的注解」来限制接口访问
@RequiresPermissions("sys:user:add")
@PreAuthorize("hasRole('admin')")
前一个是Shrio的,是基于操作的方式,后一种是SpringSecurity的,是基于角色的。
这种使用权限框架的话需要程序员进行框架配置。对于审计人员来说就稍微简单很多。首先直接看接口上有没有权限注解然后细看权限注解设置。
最后上个代码例子使用过滤器进行用户身份权限校验。过滤器(Filter)基于 Java Servlet 规范,在 Servlet 容器级别处理请求。过滤器在整个请求处理链的最前端,因此在请求到达Spring应用的任何其他组件之前,都会先经过过滤器处理
预防:
开发要有权限意识,有的开发根本不知道要做权限认证
对于用户身份标识和资源标识,要不可伪造不可轻易篡改
根据项目选择合理权限校验框架或者措施。
对于关键接口进行强加密
参考:
https://blog.csdn.net/weixin_51697044/article/details/123894899
https://blog.csdn.net/weixin_44502804/article/details/93139550
我尽力了「就这样吧」
Bye.