thinksns网站开发腾讯云 怎样建设网站
thinksns网站开发,腾讯云 怎样建设网站,网站建设公司专业开发北京网站,企帮手logo设计官网来源 | 程序员石头责编| Carol封图 | CSDN 付费下载自视觉中国之前在某厂的某次项目开发中#xff0c;项目组同学设计和实现了一个“引以为傲”#xff0c;额#xff0c;有点夸张#xff0c;不过自认为还说得过去的 feature#xff0c;结果临上线前被啪啪打脸#xff0c;… 来源 | 程序员石头责编| Carol封图 | CSDN 付费下载自视觉中国之前在某厂的某次项目开发中项目组同学设计和实现了一个“引以为傲”额有点夸张不过自认为还说得过去的 feature结果临上线前被啪啪打脸因为实现过程中因为一行代码没有标题党真的是一行代码带来的安全漏洞让我们丢失了整个服务器控制权测试环境。多亏了上线之前有公司安全团队的人会对代码进行扫描才让这个漏洞被扼杀在摇篮里。下面我们就一起来看看这个事故啊不对是故事。背景说明我们的项目是一个面向全球用户的 Web 项目用 SpringBoot 开发。在项目开发过程中离不开各种异常信息的处理比如表单提交参数不符合预期业务逻辑的处理时离不开各种异常信息例如网络抖动等的处理。于是利用 SpringBoot 各种现成的组件支持设计了一个统一的异常信息处理组件统一管理各种业务流程中可能出现的错误码和错误信息通过国际化的资源配置文件进行统一输出给用户。1、统一错误信息配置管理我们的用户遍布全球为了给各个国家用户比较好的体验会进行不同的翻译。具体而言实现的效果如下为了方便理解以“找回登录密码”这样一个业务场景来进行阐述说明。假设找回密码时需要用户输入手机或者邮箱验证码假设这个时候用户输入的验证码通过后台数据库可能是Redis对比发现已经过期。在业务代码中只需要简单的throw new ErrorCodeException(ErrorCodes.AUTHCODE_EXPIRED) 即可。具体而言针对不同国家地区不同的语言看到的效果不一样中文用户看到的提示就是“您输入的验证码已过期请重新获取”欧美用户看到的效果是“The verification code you input is expired, ...”德国用户看到的是“Der von Ihnen eingegebene Verifizierungscode ist abgelaufen, bitte wiederholen” 。我瞎找的翻译不一定准……2、统一错误信息配置管理代码实现关键信息其实就在于一个 GlobalExceptionHandler对所有 Controller 入口进行 AOP 拦截根据不同的错误信息获取相应资源文件配置的 key并从语言资源文件中读取不同国家的错误翻译信息。ControllerAdvice
public class GlobalExceptionHandler {ExceptionHandler(BadRequestException.class)ResponseBodypublic 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)ResponseBodypublic 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) {// logreturn key;}
}详细代码实现可以参考本人之前写的这篇文章一文教你实现 SpringBoot 中的自定义 Validator 和错误信息国际化配置上面有附完整的代码实现。3、基于注解的表单校验含自定义注解还有一种常见的业务场景就是后端接口需要对用户提交的表单进行校验。以“注册用户”这样的场景举例说明 注册用户时往往会提交昵称性别邮箱等信息进行注册简单起见就以这 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(messagevalidate.userRegForm.gender)private String gender;NotNullEmail(messagevalidate.userRegForm.email)private String email;
}然后在各个语言资源文件中配置好相应的错误信息提示即可。其中 Gender 就是一个自定义的注解。4、基于含自定义注解的表单校验关键代码自定义注解的实现主要的其实就是一个自定义注解的定义以及一个校验逻辑。例如定义一个自定义注解 CustomParamDocumented
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 { };DocumentedRetention(RetentionPolicy.RUNTIME)Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})interface List {CustomParam[] value();}
}校验逻辑的实现 CustomValidatorpublic class CustomValidator implements ConstraintValidatorCustomParam, String {Overridepublic 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;}}Overridepublic 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输入的参数用“11${11}”看看效果点击查看大图太 TM 神奇了居然帮我运算出来了返回message: Invalid params: 112。问题就出现在实现自定义注解进行校验的这行代码如下图所示其实最开始的时候这里直接返回了“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。点击查看大图再往后就是表达式求值了。以为这样就完了吗刚开始感觉能帮忙算简单的运算规则也就完了吧你还能把我怎么样其实这个相当于暴露了一个入口支持用户输入任意 EL 表达式进行执行。网上通过关键字 “SpEL表达式注入漏洞” 找找就能发现事情并没有想象中那么简单。我们构造恰当的 EL 表达式注意各种转义下文的输入参数相对比较明显在做什么了实际上还有更多黑科技比如各种二进制转义编码啊等等就能直接执行输入代码例如可以直接执行命令“ls -al” 返回了一个 UNIXProcess 实例命令已经被执行过了。点击查看大图比如我们执行个打开计算器的命令搞个计算器玩玩~图片放大看得更清楚我录制了一个动图来个演示可能更生动一些。这还得了吗这相当于直接在公网上提供了一个 WebShell 的功能呀你看想运行啥命令就能运行啥命令例如 ping 本人博客地址ping www.tanglei.name下面动图gif 图上传总是失败试试微信公众号嵌入视频功能演示一下整个过程从运行 ping 到 kill ping。这样岂不是直接创建一个用户然后远程登录就可以了。后果非常严重啊别人想干嘛就干嘛了。漏洞根因我们跟踪下对应的代码看看内部实现就会“恍然大悟”了。点击查看大图点击查看大图经验教训幸亏这个漏洞被扼杀在摇篮里否则后果还真的挺严重的。通过这个案例我们有啥经验和教训呢那就是作为程序员我们要对每一行代码都保持“敬畏”之心。也许就是因为你的不经意的一行代码就带来了严重的安全漏洞要是不小心被坏人利用轻则……重则……自己想象吧此外我们也应该看到程序员需要对常见的安全漏洞例如XSS/CSRF/SQL注入等等有所了解并且要有足够的安全意识其实有时候研究一些安全问题还挺好玩的例如用户权限分离运行程序的用户不应该用 root例如新建一个“web”或者“www”之类的用户并设置该用户的权限比如不能有可执行 xx 的权限之类的。本文 case如果权限进行了分离遵循最小权限原则应该也不会这么严重。本文就刚好是因为是测试环境所以没有强制实施任何时候都不要相信用户的输入必须对用户输入的进行校验和过滤又特别是针对公网上的应用。敏感信息加密保存。退一万步讲假设攻击者攻入了你的服务器如果这个时候你的数据库账户信息等配置都直接明文保存在服务器中。那数据库也被脱走了。如果可能的话需要对开发者的代码进行漏洞扫描。一些常见的安全漏洞现在应该是有现成的工具支持的。另外让专业的人做专业的事情例如要有安全团队可能你会说你们公司没有不也活的好好的哈哈只不过可能还没有被坏人盯上而已坏人也会考虑到他们的成本和预期收益的当然这就更加对我们开发者提高了要求。一些敏感权限尽量控制在少部分人手中配合相应的流程来支撑不得不说大公司繁琐的流程还是有一定道理的。如果你对本文有不同意见或者更好的建议欢迎留言参与讨论。推荐阅读云计算巨头们的背水一战整理了一份Docker系统知识从安装到熟练操作看这篇就够了| 原力计划借助大数据进行社交媒体营销企业们得这么玩追忆童年教你用Python画出儿时卡通人物AI 终极问题我们的大脑是一台超级计算机吗公链的历史交叉口PoS还能走多远真香朕在看了
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/92242.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!