越权漏洞介绍和修复参考

0x00 背景

 

https://www.xx.com/service/order.do?orderid=2280582085200280582

上图,选择orderid作为参数, 越权遍历爬取其他人的信息,类似选择某个参数或者某个接口,通过拼接或者篡改数据的ID进行请求其他ID的内容,并且返回的数据存在敏感信息,简称为越权漏洞。

恶意攻击者可以利用漏洞攻击做到:

  1. 水平越权,可以访问同级用户的身份证、手机号码、纳税信息等
  2. 垂直越权,可以访问管理员的敏感信息等。
  3. 修复思路

1、针对具有不同权限的用户,必须在UI屏蔽未授权的功能导航,必须在服务器端对访问的URL进行权限检查,防止纵向越权访问;

2、对于用户资源的访问,必须使用非直接对象引用、或访问控制检查,防止用户访问未授权的资源,防范横向越权访问。

0x01 修复思路

建议做一个过滤器,对权限进行全局校验(每次调用某个接口时,可先对权限进行校验)。大体流程是:第一步清洗URL地址,并提取Api接口名称;第二步从session中提取当前登录用户的userid;第三步提取当前用户的角色id;第四步判断当前用户对应的角色是否有权限访问当前Api接口(检查垂直越权);最后判断当前登录用户是否对目标对象有操作权限(检查水平越权)。

0x02 代码修复

首先是获取URL地址中的Api接口名称,这里对URL地址进行了一次URL解码,还是存在绕过的风险,因为当用户%2523时,就可能绕过。

public static String GetApiName(String Url) throws Exception {

    String DecodeUrl =  URLDecoder.decode(Url,"UTF-8");URL url = new URL(DecodeUrl);String ApiUrl = url.getPath();    if(ApiUrl !=null){

        String[] ApiPath = ApiUrl.split("/");String ApiName = ApiPath[ApiPath.length-1];        return ApiName;}

    return null;}

获取userid时,建议从session中获取,而不是在cookie中再新建一个userid字段,用于标识用户身份。

HttpSession session = ServletActionContext.getRequest().getSession();String userId = session.getAttribute("userId");*/

从session中提取userid后,就要查询与之对应的角色id

//UserId为用户id,RoleId为角色ID,通过UserId获取roleidpublic static int GetRoleId(int UserId) {

    Connection conn = Connect();PreparedStatement st = null;ResultSet rs = null;    int RoleId = 0;    try {

        // 查询接口访问的角色id,roleid为权限表里的角色ID字段,apiname为权限表里的API接口名称IDString sql = "select roleid from usertable where userid = ?";st = conn.prepareStatement(sql);// 这里使用PreparedStatementst.setInt(1, UserId);rs = st.executeQuery();        if(rs.next()){

            RoleId = rs.getInt("roleid");            return RoleId;}

    } catch (Exception e) {

        e.printStackTrace();        throw new RuntimeException("查询失败!");}

    return RoleId;}

校验垂直越权时,判断当前用户是否对指定的接口有访问权限,U_RoleId为用户名对应的角色id,A_RoleId为Api接口对应的角色id,Api_Name为用户尝试访问的API接口名称(这里在系统架构评审,安全设计阶段,就要检查数据库的权限表设置时,Api接口是否有指定对应的角色id)

public static boolean CheckUpPrivilege(int UserId, String Api_Name) {

    Connection conn = Connect();PreparedStatement st = null;ResultSet rs = null;    int U_RoleId = GetRoleId(UserId);    int A_RoleId = 0;    try {

        String sql = "select roleid from user_role where apiname = ?";st = conn.prepareStatement(sql);// 这里使用PreparedStatementst.setString(1, Api_Name);// 执行sql命令roleid和Role_Id,判断用户是否有权限访问对应的接口地址rs = st.executeQuery();        if(rs.next()) {

            A_RoleId = rs.getInt("roleid");// 通过比较,当用户角色id大于等于接口指定的角色id是,可以访问,部分特定接口只有指定的角色才能访问,可直接限定if (U_RoleId >= A_RoleId) {

                return true;} else {

                return false;}

        }

    } catch (Exception e) {

        e.printStackTrace();            throw new RuntimeException("查询失败!");}

    return false;}

最后再判断一下是否是水平越权,S_UserId为当前登录用户的userid,P_UserId为目标对象对应的userid,比如对订单信息进行操作时,可以先通过订单号提取与之对应的userid,再进行判断(当然,订单表,在系统架构评审,安全设计阶段,就要检查订单号是否有指定对应的用户id)。

public static boolean CheckLevelPrivilege(int S_UserId, int P_UserId) {

    if(S_UserId == P_UserId){

        return true;}

    else{

        return false;}

}

防止越权访问任意文件:
String permissionMask = System.getProperty("fileMask"):

Path path = testfile.toPath():

String [] validPermissions = { "r--------","r--r-----"}:

for (String validPermissions: validPermissions){

if (permissionMask.equals(validPermissions){

Set<PosixFilePermission> permission=

PosixFilePermissions.fromString(validPermissions):

File.setPosixFilePermissions(path.permission):

...

}

...

}
上述代码可以通过允许用户设置文件权限来防止此类文件权限操纵。如果必须确保用户拥有能够设置文件的权限,则可以采用一种间接方式,即创建一个允许用户进行指定的合法文件权限列表,并且仅允许用户从列表中进行选择。通过这种方式,用户提供的输入将不会直接更改文件权限

防止越权删除某参数的数据
@RequestMapping(value="/delete/{addrId}")
public Object remove(@PathVariable Long addrId){
Map<String, Object> respMap = new HashMap<String, Object>();
if (WebUtils.isLogged()) {
this.addressService.removeUserAddress(addrId,WebUtils.getLoggedUserId());
//关联用户身份
respMap.put(Constants.RESP_STATUS_CODE_KEY, Constants.RESP_STATUS_CODE_SUCCESS);
respMap.put(Constants.MESSAGE,"地址删除成功!");
} 

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
水平越权漏洞是一种安全漏洞,指的是攻击者通过修改或伪造请求参数、会话标识或其他身份验证机制,以获取未经授权的访问权限或执行特权操作。以下是水平越权漏洞的成因和处置建议: 成因: 1. 不恰当的身份验证和授权机制:系统可能存在缺陷的身份验证和授权机制,未正确验证用户的权限或未正确限制用户的操作范围。 2. 不安全的会话管理:会话标识可能易于猜测、被劫持或未正确管理,导致攻击者能够访问其他用户的会话数据或执行特权操作。 3. 缺乏输入验证和过滤:未正确验证和过滤用户输入,攻击者可以通过修改请求参数实现越权操作。 处置建议: 1. 实施严格的身份验证和授权机制:确保系统正确验证用户身份和权限,并根据用户的权限限制其操作范围。 2. 安全的会话管理:使用随机、复杂且不易预测的会话标识,并确保会话标识在传输和存储过程中得到适当的保护。 3. 输入验证和过滤:对用户输入进行严格验证和过滤,确保只接受有效和预期的输入,并防止攻击者通过修改请求参数来实现越权操作。 4. 最小特权原则:在授权用户时,应遵循最小特权原则,只授予用户完成所需任务所需的最低权限级别。 5. 定期安全审计:对系统进行定期的安全审计,发现和修复可能存在的水平越权漏洞。 6. 持续安全培训和意识提高:教育开发人员、管理员和用户关于水平越权漏洞的风险和防范措施,增强他们对安全问题的意识。 通过以上措施,可以有效减少水平越权漏洞的风险,并提升系统的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值