您当前的位置:首页 > 电脑百科 > 安全防护 > 服务器/网站

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

时间:2020-06-12 10:32:34  来源:  作者:

出自:程序猿石头

地址:
https://www.cnblogs.com/leitang/p/13081693.html

之前在某厂的某次项目开发中,项目组同学设计和实现了一个“引以为傲”,额,有点扩张,不过自认为还说得过去的 feature,结果临上线前被啪啪打脸,因为实现过程中因为一行代码(没有标题党,真的是一行代码)带来的安全漏洞让我们丢失了整个服务器控制权(测试环境)。多亏了上线之前有公司安全团队的人会对代码进行扫描,才让这个漏洞被扼杀在摇篮里。

下面我们就一起来看看这个事故,啊,不对,是故事。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

背景说明

我们的项目是一个面向全球用户的 Web 项目,用 SpringBoot 开发。在项目开发过程中,离不开各种异常信息的处理,比如表单提交参数不符合预期,业务逻辑的处理时离不开各种异常信息(例如网络抖动等)的处理。于是利用 SpringBoot 各种现成的组件支持,设计了一个统一的异常信息处理组件,统一管理各种业务流程中可能出现的错误码和错误信息,通过国际化的资源配置文件进行统一输出给用户。

统一错误信息配置管理

我们的用户遍布全球,为了给各个国家用户比较好的体验会进行不同的翻译。具体而言,实现的效果如下,为了方便理解,以“找回登录密码”这样一个业务场景来进行阐述说明。

假设找回密码时,需要用户输入手机或者邮箱验证码,假设这个时候用户输入的验证码通过后台数据库(可能是redis)对比发现已经过期。在业务代码中,只需要简单的 throw new ErrorCodeException(
ErrorCodes.AUTHCODE_EXPIRED) 即可。具体而言,针对不同国家地区不同的语言看到的效果不一样:

  • 中文用户看到的提示就是“您输入的验证码已过期,请重新获取”;
  • 欧美用户看到的效果是“The verification code you input is expired, ...”;
  • 德国用户看到的是:“Der von Ihnen eingegebene Verifizierungscode ist abgelaufen, bitte wiederholen” 。(我瞎找的翻译,不一定准)
  • ……

统一错误信息配置管理代码实现

关键信息其实就在于一个 GlobalExceptionHandler,对所有Controller 入口进行 AOP 拦截,根据不同的错误信息,获取相应资源文件配置的 key,并从语言资源文件中读取不同国家的错误翻译信息。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BadRequestException.class)
    @ResponseBody
    public ResponseEntity handle(HttpServletRequest request, BadRequestException e){
        String i18message = getI18nMessage(e.getKey(), request);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Response.error(e.getCode(), i18message));
    }
    
    @ExceptionHandler(ErrorCodeException.class)
    @ResponseBody
    public ResponseEntity handle(HttpServletRequest request, ErrorCodeException e){
        String i18message = getI18nMessage(e.getKey(), request);
        return ResponseEntity.status(HttpStatus.OK).body(Response.error(e.getCode(), i18message));
    }
}
一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

不同语言的资源文件示例

private String getI18nMessage(String key, HttpServletRequest request) {
   try {
       return messageSource.getMessage(key, null, LanguaggeUtils.currentLocale(request));
   } catch (Exception e) {
       // log
       return key;
   }
}

基于注解的表单校验(含自定义注解)

还有一种常见的业务场景就是后端接口需要对用户提交的表单进行校验。以“注册用户”这样的场景举例说明, 注册用户时,往往会提交昵称,性别,邮箱等信息进行注册,简单起见,就以这 3 个属性为例。

定义的表单如下:

public class UserRegForm {
 private String nickname;
 private String gender;
 private String email;
}

对于表单的约束,我们有:

  • 昵称字段:“nickname” 必填,长度必须是 6 到 20 位;
  • 性别字段:“gender” 可选,如果填了,就必须是“Male/Female/Other/”中的一种。说啥,除了男女还有其他?对,是的。毕竟全球用户嘛,你去看看非死不可,还有更多。
  • 邮箱: “email”,必填,必须满足邮箱格式。

对于以上约束,我们只需要在对应的字段上添加如下注解即可。

public class UserRegForm {
 @Length(min = 6, max = 20, message = "validate.userRegForm.nickname")
 private String nickname;

 @Gender(message="validate.userRegForm.gender")
 private String gender;

 @NotNull
 @Email(message="validate.userRegForm.email")
 private String email;
}

然后在各个语言资源文件中配置好相应的错误信息提示即可。其中, @Gender 就是一个自定义的注解。

基于含自定义注解的表单校验关键代码

自定义注解的实现主要的其实就是一个自定义注解的定义以及一个校验逻辑。 例如定义一个自定义注解 CustomParam:

@Documented
@Constraint(validatedBy = CustomValidator.class)
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomParam {
    String message() default "name.tanglei.www.validator.CustomArray.defaultMessage";

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default { };

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
    @interface List {
        CustomParam[] value();
    }
}

校验逻辑的实现 CustomValidator:

public class CustomValidator implements ConstraintValidator<CustomParam, String> {
    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (null == s || s.isEmpty()) {
            return true;
        }
        if (s.equals("tanglei")) {
            return true;
        } else {
            error(constraintValidatorContext, "Invalid params: " + s);
            return false;
        }
    }

    @Override
    public void initialize(CustomParam constraintAnnotation) {
    }

    private static void error(ConstraintValidatorContext context, String message) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
    }
}

上面例子只为了阐述说明问题,其中校验逻辑没有实际意义,这样,如果输入参数不满足条件,就会明确提示用户输入的哪个参数不满足条件。例如输入参数 xx,则会直接提示:Invalid params: xx。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

这个跟第一部分的处理方式类似,因为现有的 validator 组件实现中,如果违反相应的约束也是一种抛异常的方式实现的,因此只需要在上述的 GlobalExceptionHandler中添加相应的异常信息即可,这里就不详述了。 这不是本文的重点,这里就不详细阐述了。

场景重现

一切都显得很完美,直到上线前代码提交至安全团队扫描,就被“啪啪打脸”,扫描报告反馈了一个严重的安全漏洞。而这个安全漏洞,属于很高危的远程代码执行漏洞。

用前文提到的自定义 Validator,输入的参数用: “1+1=${1+1}”,看看效果:

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

太 TM 神奇了,居然帮我运算出来了,返回 "message": "Invalid params: 1+1=2"。

问题就出现在实现自定义注解进行校验的这行代码(如下图所示):

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

其实,最开始的时候,这里直接返回了“Invalid params”,当初为了更好的用户体验,要明确告诉用户哪个参数没有通过校验,因此在输出的提示上加上了用户输入的字段,也就是上面的"Invalid params: " + s,没想到,这闯了大祸了(回过头来想,感觉这里没必要这么详细啊,因为前端已经有相应的校验了,正常情况下回拦住,针对不守规矩的用非常规手段来的接口请求,直接返回校验不通过就行了,毕竟不是对外提供的 OpenAPI 服务)。

仔细看,这个方法实际上是 
ConstraintValidatorContext这个接口中声明的,看方法名字其实能知道输入参数是一个字符串模板,内部会进行解析替换的(这其实也符合“见名知意”的良好编程习惯)。(教训:大家应该把握好自己写的每一行代码背后实际在做什么。)

/* ......
 * @param messageTemplate new un-interpolated constraint message
 * @return returns a constraint violation builder
 */
ConstraintViolationBuilder buildConstraintViolationWithTemplate(String messageTemplate);

这个 case,源码调试进去之后,就能跟踪到执行翻译阶段,在如下方法中: 
org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator.interpolateMessage。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

再往后,就是表达式求值了。 [图片上传失败...(image-9239c-1591863495667)]

以为就这样就完了吗?

刚开始感觉,能帮忙算简单的运算规则也就完了吧,你还能把我怎么样?其实这个相当于暴露了一个入口,支持用户输入任意 EL 表达式进行执行。网上通过关键字 “SpEL表达式注入漏洞” 找找,就能发现事情并没有想象中那么简单。

我们构造恰当的 EL 表达式(注意各种转义,下文的输入参数相对比较明显在做什么了,实际上还有更多黑科技,比如各种二进制转义编码啊等等),就能直接执行输入代码,例如:可以直接执行命令,“ls -al”, 返回了一个 UNIXProcess 实例,命令已经被执行过了。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

比如,我们执行个打开计算器的命令,搞个计算器玩玩~

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

我录制了一个动图,来个演示可能更生动一些。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

这还得了吗?这相当于提供了一个 webshell 的功能呀,你看想运行啥命令就能运行啥命令,例如 ping 本人博客地址(ping www.tanglei.name),下面动图演示一下整个过程(从运行 ping 到 kill ping)。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

岂不是直接创建一个用户,然后远程登录就可以了。后果很严重啊,别人想干嘛就干嘛了。

我们跟踪下对应的代码,看看内部实现,就会“恍然大悟”了。

一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 


一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权

 

经验教训

幸亏这个漏洞被扼杀在摇篮里,否则后果还真的挺严重的。通过这个案例,我们有啥经验和教训呢?那就是作为程序员我们要对每一行代码都保持“敬畏”之心。也许就是因为你的不经意的一行代码就带来了严重的安全漏洞,要是不小心被坏人利用,轻则……重则……(自己想象吧)

此外,我们也应该看到,程序员需要对常见的安全漏洞(例如XSS/CSRF/SQL注入等等)有所了解,并且要有足够的安全意识(其实有时候研究一些安全问题还挺好玩的)。例如:

  • 用户权限分离:运行程序的用户不应该用 root,例如新建一个“web”或者“www”之类的用户,并设置该用户的权限,比如不能有可执行 xx 的权限之类的。本文 case,如果权限进行了分离(遵循最小权限原则),应该也不会这么严重。(本文就刚好是因为是测试环境,所以没有强制实施)
  • 任何时候都不要相信用户的输入,必须对用户输入的进行校验和过滤,又特别是针对公网上的应用。
  • 敏感信息加密保存。退一万步讲,假设攻击者攻入了你的服务器,如果这个时候,你的数据库账户信息等配置都直接明文保存在服务器中。那数据库也被拖走了。

如果可能的话,需要对开发者的代码进行漏洞扫描。一些常见的安全漏洞现在应该是有现成的工具支持的。另外,让专业的人做专业的事情,例如要有安全团队,可能你会说你们公司没有不也活的好好的,哈哈,只不过可能还没有被坏人盯上而已,坏人也会考虑到他们的成本和预期收益的,当然这就更加对我们开发者提高了要求。一些敏感权限尽量控制在少部分人手中,配合相应的流程来支撑(不得不说,大公司繁琐的流程还是有一定道理的)。

毕竟我不是专业研究Web安全的,以上说的可能也不一定对,如果你有不同意见或者更好的建议欢迎留言参与讨论。



Tags:安全漏洞   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
“nfs”文件系统的mount()系统调用存在双重获取漏洞。理论上,Double Fetch是一个有条件的竞争漏洞,这是一场内核模式和用户模式之间的数据访问的较量。Double fetch类型漏洞...【详细内容】
2021-08-14  Tags: 安全漏洞  点击:(70)  评论:(0)  加入收藏
关于工具现有工具现在,现成的污点分析工具已经有很多了。其中,我最感兴趣的是Triton和bincat,因为两者已经相当成熟。然而,我们却无法使用这两种工具,因为它们不支持目标设备所...【详细内容】
2021-08-12  Tags: 安全漏洞  点击:(94)  评论:(0)  加入收藏
导读:工业和信息化部、国家互联网信息办公室、公安部近日联合印发《网络产品安全漏洞管理规定》。《规定》旨在维护国家网络安全,保护网络产品和重要网络系统的安全稳定运行;规...【详细内容】
2021-07-14  Tags: 安全漏洞  点击:(57)  评论:(0)  加入收藏
在讨论如何在应用程序中应用安全性之前,您应该首先了解如何保护应用程序。为了进行恶意操作,攻击者会识别并利用应用程序的漏洞。我们经常将漏洞描述为一种弱点,它可以允许执行...【详细内容】
2021-04-21  Tags: 安全漏洞  点击:(186)  评论:(0)  加入收藏
01 事件背景6月25日, Apache 官方安全团队通过邮件公开报告了一个高危漏洞,邮件中介绍了 HTTP/2 拒绝服务漏洞的细节及解决方案。如下图所示:漏洞详情链接:http://mail-archives...【详细内容】
2020-07-09  Tags: 安全漏洞  点击:(113)  评论:(0)  加入收藏
近日,浙江大学网络空间安全学院院长任奎团队、加拿大麦吉尔大学、多伦多大学研究团队共同发表了一项聚焦智能手机窃听攻击的研究成果:智能手机APP可在用户毫不知情时,利用手机...【详细内容】
2020-06-15  Tags: 安全漏洞  点击:(84)  评论:(0)  加入收藏
出自:程序猿石头地址: https://www.cnblogs.com/leitang/p/13081693.html之前在某厂的某次项目开发中,项目组同学设计和实现了一个“引以为傲”,额,有点扩张,不过自认为还说得过去...【详细内容】
2020-06-12  Tags: 安全漏洞  点击:(75)  评论:(0)  加入收藏
中国经济周刊-经济网讯 4月23日,有媒体报道称,苹果公司正计划修复一个漏洞,此前一家安全公司表示,这个漏洞可能已令超过5亿部iPhone易受黑客攻击,而且iPad上也存在这个漏洞。苹果...【详细内容】
2020-04-23  Tags: 安全漏洞  点击:(85)  评论:(0)  加入收藏
前言编写安全代码是一件很难的事情。Python也不例外,即使在标准库中,也有记录在案的编写应用程序的安全漏洞。下面是Python应用程序中最常见的10个安全陷阱以及相关解决办法。...【详细内容】
2020-04-20  Tags: 安全漏洞  点击:(34)  评论:(0)  加入收藏
该系统是微软 47000 名开发人员进行的 1300 万个工作项目和 bug 的数据集进行训练的,这些工作项目和 bug 数据存储在 AzureDevOps 和 GitHub 的存储库中。作者/来源: 安华金...【详细内容】
2020-04-19  Tags: 安全漏洞  点击:(60)  评论:(0)  加入收藏
▌简易百科推荐
在最近的一波攻击中,黑客利用多个插件中未修补的漏洞攻击了 160 万个 WordPress 网站。 易受攻击的插件对 WordPress 网站产生了的巨大攻击数据。 Wordfence 最近发现 WordPr...【详细内容】
2021-12-16  蚁安    Tags:WordPress   点击:(9)  评论:(0)  加入收藏
事件起因从安全分析系统里面发现一条带有病毒的下载,然后针对这条记录展开了一系列的分析分析过程1.登录到被感染服务器,查看系统状况,hadoop 这个用户在 2020/6/18 20:32 从这...【详细内容】
2021-11-23  Z2990Lig    Tags:SSH   点击:(32)  评论:(0)  加入收藏
1、除了服务器需要用的一些正规软件,其它都不要安装。2、在用户中把administrator改名,这样做的目的是即使对方暴破了我们的密码用户名也不容易猜住,相当于又加了一道关卡。...【详细内容】
2021-11-01  IT小哥吧    Tags:服务器   点击:(37)  评论:(0)  加入收藏
账户安全(1)更名administrator本地用户并禁用guest账户步骤:点击“开始”,找到“管理工具”,点击里面的“计算机管理”,找到“本地用户和组” (2)设定账户锁定策略尝试5次失败...【详细内容】
2021-10-12  Kali与编程  今日头条  Tags:Windows主机   点击:(62)  评论:(0)  加入收藏
本文主要介绍以Microsoft的Windows Server 2019 ,版本:Datacenter(Domain Controller)安全加固保护.企业随着规模不断扩大,业务增多,信息安全建设是企业里一条只有重点没有终点...【详细内容】
2021-09-17  Vireshark    Tags:服务器安全   点击:(64)  评论:(0)  加入收藏
目录常见共享命令IPC$IPC$的利用条件1:开启了139、445端口2:目标主机开启了IPC$共享3:IPC连接报错IPC空连接空连接可以做什么?(毫无作用)IPC$非空连接IPC$非空连接可以做什么?di...【详细内容】
2021-09-16  网络说安全    Tags:系统安全   点击:(86)  评论:(0)  加入收藏
昨天一个老哥找到我,说他的服务器这几天一直被CC攻击,问我这边有没有什么解决的方法? 近年来,网络攻击事件越来越频繁,最常见的就是CC攻击和DDOS攻击,主要的区别就是针对的对象不...【详细内容】
2021-09-10  小蚁GDRAGON    Tags:cc攻击   点击:(58)  评论:(0)  加入收藏
网站页面上的登录操作,通常都是输入帐号密码,传输至网站后台验证。在网站页面、数据传输中,通过技术手段,都可以得到用户输入的信息,并可以修改,从而发起网络攻击。典型的如:使用自...【详细内容】
2021-08-30  修丹道的程序猿    Tags:登录方式   点击:(62)  评论:(0)  加入收藏
网络安全研究人员披露了一类影响主要 DNS 即服务 (DNSaaS) 提供商的新漏洞,这些漏洞可能允许攻击者从企业网络中窃取敏感信息。基础设施安全公司 Wiz 的研究人员 Shir Tamar...【详细内容】
2021-08-12  零日时代    Tags:漏洞   点击:(66)  评论:(0)  加入收藏
001暴力破解1. 指定用户名爆破密码传统型爆破思路,用户名可以通过猜测或者信息收集获得。猜测:admin、网站域名等信息收集:新闻发布人、whoami等2. 指定密码爆破用户名如果是后...【详细内容】
2021-07-23  KaliMa  今日头条  Tags:登陆框   点击:(85)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条