本文用到的技术

AOP

ESAPI

关于AOP技术

AOP(Aspect-Oriented Programming)面向切面编程。切面是什么?切面表示从业务逻辑分离出来的横切逻辑,比如性能监控、日志记录、权限控制,这些功能可从核心逻辑代码中抽离出去。也就是说AOP可以解决代码耦合问题,让职责更加单一。

这里要讲的是利用AOP技术解决代码安全问题。把安全代码从业务逻辑中分离出来,让其单一的解决安全问题。

优势:不影响业务代码,修复安全漏洞的时候,可以对原代码很好的继承,不需修改原代码(基于配置定义切点的时候)。

将AOP技术应用于安全技术的案例很少,网上很难找到较多示例代码。

关于ESAPI

OWASP Enterprise Security API (ESAPI)

ESAPI (OWASP企业安全应用程序接口)是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序。ESAPI接口库被设计来使程序员能够更容易的在现有的程序中引入安全因素。ESAPI库也可以成为作为新程序开发的基础。

通俗点说ESAPI是OWASP提供的一个安全开发API库。

优势:对比自己开发的安全处理代码更成熟稳定。

ESAPI具体的使用实际也是比较少,网上也很难找到较多示例代码。开发过程比较困难点

AOP 技术做 XSS 防御

OWASP提供了几种XSS防御的方法,包括阻止非信任的数据插入,escaping HTML输入、escaping attribute、escaping JavaScript、以及escaping几种其他类型。ESAPI提供了多种encoding库。另外也可以采用白名单validate方法(比如字母数字),也可以自定义正则表达式。

AOP技术实现ESAPI提供的encoding和validation库,来做XSS攻击的防御工作。

ESAPI提供的几种encoding方法:

  • 将用户数据输出到html body某处时,须经过html转义。ESAPI.encoder().encodeForHTML( request.getParameter( “input” ) )
  • 将用户数据输出到html标签的属性时,须经过标签属性的转义。ESAPI.encoder().encodeForHTMLAttribute( request.getParameter( “input” ) )
  • 将用户数据输出到JavaScript数据域时,须经过JavaScript转义。ESAPI.encoder().encodeForJavaScript( request.getParameter( “input” ) )
  • 将用户数据输出到URL的参数时,须经过URL转义。ESAPI.encoder().encodeForURL( request.getParameter( “input” ) )

方案逻辑

实现

定义切点的注解

在需要进行XSS防御的方法前使用相应的注解。

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface XSSAllTag {
  4. }
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface XSSBeanTag {
  4. }
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface XSSStringTag {
  4. }

定义切面类

拦截指定方法,遍历String类型参数,和数据模型(JAVABean)中的String属性,并对其进行XSS validate。

  1. @Aspect
  2. @Component
  3. public class SecXSSAspect {
  4. @SuppressWarnings("unchecked")
  5. @Around(value = "@annotation(com.tony.security.aspectbox.XSSAllTag)")
  6. public Object xssAllAdvice(ProceedingJoinPoint pjp) throws Throwable {
  7. // 获取切入方法的参数
  8. Object[] args = pjp.getArgs();
  9. // 获取切入方法
  10. Method method = ((MethodSignature) pjp.getSignature()).getMethod();
  11. // 获取参数的类型
  12. Class<?>[] paramTypes = method.getParameterTypes();
  13. // 获取参数名
  14. ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
  15. String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
  16. for (int i = 0; i < paramTypes.length; i++) {
  17. System.out.println("parameterName" + i + ": " + parameterNames[i]);
  18. if (paramTypes[i].equals(String.class)) {
  19. if (args[i] != null && args[i] != "" && !parameterNames[i].equalsIgnoreCase("password")) {
  20. args[i] = XSSValidation.escapeHTML((String) args[i]);
  21. }
  22. } else if (!GeneralHelper.isSimpleType(paramTypes[i]) && !GeneralHelper.isSpringType(paramTypes[i])) {
  23. if (args[i] != null) {
  24. Class<?> class1 = args[i].getClass();
  25. Method[] ms = class1.getDeclaredMethods();
  26. for (int j = 0; j < ms.length; j++) {
  27. // 遍历所有返回为String类型的get方法(不包含password字段),获取并处理get返回值,调用其set方法重写安全编码的值
  28. if (ms[j].getName().startsWith("get") && ms[j].getReturnType().equals(String.class)) {
  29. if (!ms[j].getName().toLowerCase().contains("password")) {
  30. String result = XSSValidation.escapeHTML((String) ms[j].invoke(args[i]));
  31. String methodName = ms[j].getName().replace("get", "set");
  32. Method setM = class1.getDeclaredMethod(methodName, String.class);
  33. setM.invoke(args[i], result);
  34. }
  35. }
  36. }
  37. }
  38. } else {
  39. continue;
  40. }
  41. }
  42. return pjp.proceed();
  43. }
  44. ...
  45. }

使用ESAPI库处理XSS攻击input

针对XSS攻击不同location与类别,提供相应的encoding方法。

  1. public abstract class XSSValidation {
  2. public static String REGEX_ALPHANUMERIC = "AlphaNumberic";
  3. public static String REGEX_ALPHA = "Alpha";
  4. public static String REGEX_NUMERIC = "Numeric";
  5. public static String REGEX_EMAIL = "Email";
  6. public static String REGEX_ZIP_CODE = "ZipCode";
  7. public static String REGEX_IP_ADDRESS = "IPAddress";
  8. public static String REGEX_SSN = "SSN";
  9. public XSSValidation() {
  10. }
  11. public static String escapeCustomString(String s, String regex,
  12. int maxLength) {
  13. Pattern p = ESAPI.securityConfiguration().getValidationPattern(regex);
  14. if (p == null)
  15. p = Pattern.compile(regex);
  16. // Sending pattern directly.
  17. try {
  18. return ESAPI.validator().getValidInput("CUSTOM_STRING_ESCAPE", s,
  19. regex, maxLength, false, false);
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. String resultString = "";
  23. Matcher m = p.matcher(s);
  24. while (m.find()) {
  25. resultString += m.group(0);
  26. }
  27. return resultString;
  28. }
  29. }
  30. public static String escapeJavaScript(String s) {
  31. return ESAPI.encoder().encodeForJavaScript(s);
  32. }
  33. public static String escapeCSS(String s) {
  34. return ESAPI.encoder().encodeForCSS(s);
  35. }
  36. public static String escapeHTML(String s) {
  37. return ESAPI.encoder().encodeForHTML(s);
  38. }
  39. public static String escapeHTMLAttribute(String s) {
  40. return ESAPI.encoder().encodeForHTMLAttribute(s);
  41. }
  42. public static String escapeURL(String s) throws EncodingException {
  43. return ESAPI.encoder().encodeForURL(s);
  44. }
  45. @SuppressWarnings("finally")
  46. public static String validateCreditCard(String s) {
  47. try {
  48. s = ESAPI.validator().getValidCreditCard("CREDIT_CARD", s, false);
  49. } catch (ValidationException e) {
  50. s = "VALIDATION FAILED " + s;
  51. e.printStackTrace();
  52. } catch (Exception e) {
  53. s = "VALIDATION FAILED " + s;
  54. e.printStackTrace();
  55. } finally {
  56. return s;
  57. }
  58. }
  59. }

判定是否简单数据类型

  1. public class GeneralHelper {
  2. /** 简单数据类型集合 */
  3. public static final Set<Class<?>> SMIPLE_CLASS_SET = new HashSet<Class<?>>(18);
  4. /** Spring Controller常用数据类型集合 */
  5. public static final Set<Class<?>> SPRING_CLASS_SET = new HashSet<Class<?>>(18);
  6. static
  7. {
  8. SMIPLE_CLASS_SET.add(int.class);
  9. SMIPLE_CLASS_SET.add(long.class);
  10. SMIPLE_CLASS_SET.add(float.class);
  11. SMIPLE_CLASS_SET.add(double.class);
  12. SMIPLE_CLASS_SET.add(byte.class);
  13. SMIPLE_CLASS_SET.add(char.class);
  14. SMIPLE_CLASS_SET.add(short.class);
  15. SMIPLE_CLASS_SET.add(boolean.class);
  16. SMIPLE_CLASS_SET.add(Integer.class);
  17. SMIPLE_CLASS_SET.add(Long.class);
  18. SMIPLE_CLASS_SET.add(Float.class);
  19. SMIPLE_CLASS_SET.add(Double.class);
  20. SMIPLE_CLASS_SET.add(Byte.class);
  21. SMIPLE_CLASS_SET.add(Character.class);
  22. SMIPLE_CLASS_SET.add(Short.class);
  23. SMIPLE_CLASS_SET.add(Boolean.class);
  24. SMIPLE_CLASS_SET.add(String.class);
  25. SMIPLE_CLASS_SET.add(Date.class);
  26. }
  27. /** 检查 clazz 是否为简单数据类型 */
  28. public final static boolean isSimpleType(Class<?> clazz)
  29. {
  30. return SMIPLE_CLASS_SET.contains(clazz);
  31. }
  32. static
  33. {
  34. SPRING_CLASS_SET.add(Model.class);
  35. SPRING_CLASS_SET.add(ModelAndView.class);
  36. SPRING_CLASS_SET.add(HttpSession.class);
  37. }
  38. /** 检查 clazz 是否为Spring Controller常用数据类型 */
  39. public final static boolean isSpringType(Class<?> clazz)
  40. {
  41. return SPRING_CLASS_SET.contains(clazz);
  42. }
  43. }

Controller中使用

在Contoller层使用前面定义的注解,进行XSS攻击防护。

  1. @XSSAllTag
  2. @RequestMapping(value="/user/addUser")
  3. public ModelAndView addUser(String flag,@ModelAttribute User user,ModelAndView mv){
  4. if(flag.equals("1")){
  5. mv.setViewName("user/showAddUser");
  6. }else{
  7. hrmService.addUser(user);
  8. mv.setViewName("redirect:/user/selectUser");
  9. }
  10. return mv;
  11. }

AOP技术做FileUpload防御

方案逻辑

定义注解

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface FileSuffixTag {
  4. }

定义切面

  1. @Aspect
  2. @Component
  3. public class FileUploadAspect {
  4. @SuppressWarnings("unchecked")
  5. @Around(value = "@annotation(com.tony.security.aspectbox.FileSuffixTag)")
  6. public Object fileSuffixAdvice(ProceedingJoinPoint pjp) throws Throwable {
  7. boolean result = true;
  8. // 获取切入方法的参数
  9. Object[] args = pjp.getArgs();
  10. // 获取切入方法
  11. Method method = ((MethodSignature) pjp.getSignature()).getMethod();
  12. // 获取参数的类型
  13. Class<?>[] paramTypes = method.getParameterTypes();
  14. // 获取参数名
  15. ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
  16. String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
  17. for (int i = 0; i < paramTypes.length; i++) {
  18. System.out.println("parameterName" + i + ": " + parameterNames[i]);
  19. if (!GeneralHelper.isSimpleType(paramTypes[i]) && !GeneralHelper.isSpringType(paramTypes[i])) {
  20. if (args[i] != null) {
  21. Class<?> class1 = args[i].getClass();
  22. Method[] ms = class1.getDeclaredMethods();
  23. for (int j = 0; j < ms.length; j++) {
  24. // 遍历所有返回为MutipartFile类型的get方法
  25. if (ms[j].getName().startsWith("get") && ms[j].getReturnType().equals(MultipartFile.class)) {
  26. MultipartFile file = (MultipartFile) ms[j].invoke(args[i]);
  27. if (file !=null && !file.isEmpty()) {
  28. result = FileUploadValidation.suffixValid(file);
  29. System.out.println(result);
  30. }
  31. }
  32. }
  33. }
  34. }
  35. }
  36. if (result == true) {
  37. System.out.println("正确上传");
  38. return pjp.proceed();
  39. }else{
  40. System.out.println("非法上传");
  41. ModelAndView mv = new ModelAndView();
  42. mv.addObject("message","非法上传");
  43. mv.setViewName("forward:/loginForm");
  44. return mv;
  45. }
  46. }
  47. }

使用ESAPI中的文件上传校验库

  1. public abstract class FileUploadValidation {
  2. private static final String GIF_IMAGE_EXTENSION = "gif";
  3. private static final String JPEG_IMAGE_EXTENSION = "jpeg";
  4. private static final String JPG_IMAGE_EXTENSION = "jpg";
  5. private static final String PNG_IMAGE_EXTENSION = "png";
  6. public static final String FILE_UPLOAD_CONTEXT = "fileUpload";
  7. public static boolean allowNull = false;
  8. public FileUploadValidation() {
  9. }
  10. @SuppressWarnings("null")
  11. public static boolean suffixValid(MultipartFile file)
  12. throws IntrusionException, ValidationException {
  13. String filename = file.getOriginalFilename();
  14. List<String> allowedExtensions = new ArrayList<String>();
  15. allowedExtensions.add(GIF_IMAGE_EXTENSION);
  16. allowedExtensions.add(JPEG_IMAGE_EXTENSION);
  17. allowedExtensions.add(JPG_IMAGE_EXTENSION);
  18. allowedExtensions.add(PNG_IMAGE_EXTENSION);
  19. return ESAPI.validator().isValidFileName(FILE_UPLOAD_CONTEXT,filename,allowedExtensions,allowNull);
  20. }
  21. }

Controller中使用

  1. @FileSuffixTag
  2. @RequestMapping(value="/document/addDocument")
  3. public ModelAndView addDocument(String flag,@ModelAttribute Document document,ModelAndView mv,HttpSession session) throws Exception{
  4. if(flag.equals("1")){
  5. mv.setViewName("document/showAddDocument");
  6. }else{
  7. String path = session.getServletContext().getRealPath("/upload");
  8. String fileName = document.getFile().getOriginalFilename();
  9. System.out.println("path -->>"+path);
  10. System.out.println("fileName -->>"+fileName);
  11. document.getFile().transferTo(new File(path+File.separator+fileName));
  12. document.setFilename(fileName);
  13. User user = (User) session.getAttribute(HrmConstants.USER_SESSION);
  14. document.setUser(user);
  15. hrmService.addDocument(document);
  16. mv.setViewName("redirect:/document/selectDocument");
  17. }
  18. return mv;
  19. }

AOP技术做SQL注射防御

消除SQL注射漏洞主要有3种方法:参数化查询、存储过程(类似参数化查询,但是query存在在数据库上,供应用调用)、escaping用户输入。另外一种是做白名单验证,阻止查询中输入非法的格式。我这里选择escaping用户输入和白名单validate。其优点是可以不修改原代码。Aspects能去拦截和分析query,然后在执行前escape所有的表达式(expressions,可能包含恶意内容)。

而参数化查询需要重写动态查询代码,存储过程需要开发move所有查询到数据库层。都需要修改原有代码,可能引入bug和未知行为。此外OWASP提供了一个安全的encoding库,可以直接调用。

方案逻辑

SQL Injection validator 逻辑

Aspect拦截到query后,先进行注释移除,然后利用JSqlParser API对query的where进行解析,输出简单的expression List。

遍历上一步获得的simpleExpressions,对其进行语义重复检测(类似1=1),如果检测到有语义重复,就替换成“1=2”。

最后对类型为String的value进行encode。

https://github.com/JSQLParser/JSqlParser/wiki

ESAPI Encode

  1. ESAPI.encoder().encodeForSQL()

编码结果样例:

输入:foo” and 1 = 2 
输出:foo\” and 1 \= 2

SQL Parser逻辑

*本文作者:tony86,转载请注明来自 FreeBuf.COM

AOP技术应用于安全防御与漏洞修复的更多相关文章

  1. 2018-2019-2 网络对抗技术 20165322 Exp6 信息搜集与漏洞扫描

    2018-2019-2 网络对抗技术 20165322 Exp6 信息搜集与漏洞扫描 目录 实验原理 实验内容与步骤 各种搜索技巧的应用 DNS IP注册信息的查询 基本的扫描技术 漏洞扫描 基础问题 ...

  2. 20165214 2018-2019-2 《网络对抗技术》Exp6 信息搜集与漏洞扫描 Week9

    <网络对抗技术>Exp6 信息搜集与漏洞扫描 Week9 一.实验目标与内容 1.实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 2.实践内容 (1)各种搜索技巧的应用 使用搜索 ...

  3. 面向侧面的程序设计AOP-------《三》.Net平台AOP技术概览

    本文转载自张逸:晴窗笔记 .Net平台与Java平台相比,由于它至今在服务端仍不具备与unix系统的兼容性,也不具备类似于Java平台下J2EE这样的企业级容器,使得.Net平台在大型的企业级应用上, ...

  4. C#.NET利用ContextBoundObject和Attribute实现AOP技术--AOP事务实现例子

    我前两天看见同事用写了用AOP技术实现缓存的方案,于是好奇看了一下这是怎么实现的.原来是用了.NET中的一个类ContextBoundObject和Attribute相关技术.其实个类在.NET Fr ...

  5. AOP技术基础

    1.引言 2.AOP技术基础 3.Java平台AOP技术研究 4..Net平台AOP技术研究 2.1 AOP技术起源 AOP技术的诞生并不算晚,早在1990年开始,来自Xerox Palo Alto ...

  6. 2018-2019-2 20165232 《网络对抗技术》 Exp6 信息搜集与漏洞扫描

    2018-2019-2 20165232 <网络对抗技术> Exp6 信息搜集与漏洞扫描 一.实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 二.实践内容. 各种搜索技巧的应 D ...

  7. 2018-2019-2 网络对抗技术 20165237 Exp6 信息搜集与漏洞扫描

    2018-2019-2 网络对抗技术 20165237 Exp6 信息搜集与漏洞扫描 实验目标 1 各种搜索技巧的应用: 2 DNS IP注册信息的查询: 3 基本的扫描技术: 主机发现.端口扫描.O ...

  8. 2018-2019-2 20165221 【网络对抗技术】-- Exp6 信息搜集与漏洞扫描

    2018-2019-2 20165221 [网络对抗技术]-- Exp6 信息搜集与漏洞扫描 目录 1. 实践目标 2. 实践内容 3. 各种搜索技巧的应用 a. 搜索网址的目录结构 b.使用IP路由 ...

  9. 2018-2019-2 20165325 《网络对抗技术》 Exp6 信息搜集与漏洞扫描

    2018-2019-2 20165325 <网络对抗技术> Exp6 信息搜集与漏洞扫描 实验内容(概要) 1 各种搜索技巧的应用: 2 DNS IP注册信息的查询: 3 基本的扫描技术 ...

随机推荐

  1. Python+Selenium中级篇之-Python读取配置文件内容

    本文来介绍下Python中如何读取配置文件.任何一个项目,都涉及到了配置文件和管理和读写,Python支持很多配置文件的读写,这里我们就介绍一种配置文件格式的读取数据,叫ini文件.Python中有一 ...

  2. Python+Selenium练习篇之2-利用ID定位元素

    在前面一篇文章,我们介绍了如何摘取页面字段,通过正则进行匹配符合要求的字段.如果感觉有点困难,不能立马理解,没有关系.把字符串摘取放到第一篇,是因为自动化测试脚本,经常要利用字符串操作,字符串切割,查 ...

  3. 微信小程序简单的数据表格及查询功能

    简介: 此项目是一个前后端分离的小demo, 开发工具:idea+微信小程序开发工具 前端:界面布局样式和js的跳转 后端:依靠SpringBoot的业务逻辑层 项目的码云地址: https://gi ...

  4. Socket 编程中,TCP 流的结束标志与粘包问题

    因为 TCP 本身是无边界的协议,因此它并没有结束标志,也无法分包. socket和文件不一样,从文件中读,读到末尾就到达流的结尾了,所以会返回-1或null,循环结束,但是socket是连接两个主机 ...

  5. 服务器(centos7)用nginx挂出多个网站的配置

    前提: 装好环境的centos7系统(其他版本也行),装好ngnix: 推荐:http://www.cnblogs.com/alsy/p/5296244.html 把你的项目上传到服务器上(可以用Xf ...

  6. 共鸣(resonance)

    共鸣(resonance) 题目描述 GHQ通过在24区引起基因组共鸣,从而引发了第二次失落的圣诞. 24区的地图可以视为一个二维平面.GHQ在24区布置了m架发射塔,而葬仪社也建立了n个据点.要阻止 ...

  7. StringBuilder与StringBuffer

    转:http://www.cnblogs.com/pepcod/archive/2013/02/16/2913557.html JAVA中用于处理字符串常用的有三个类: java.lang.Strin ...

  8. POJ1595 Prime Cuts

    Prime Cuts Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11961   Accepted: 4553 Descr ...

  9. 冬训 day2

    模拟枚举... A - New Year and Buggy Bot(http://codeforces.com/problemset/problem/908/B) 暴力枚举即可,但是直接手动暴力会非 ...

  10. Eclipse与MyEclipse修改注释字体颜色

    修改配置路劲 Window--->Preferences--->Java--->Editor--->Syntax Coloring--->Element--->Co ...