麦肯锡:速度与激情,中国物流乘浪前行(报告)

前言

JFinal-layui 极速开发企业应用管理系统,是以 JFinal+layui 为核心的企业应用项目架构,利用 JFinal 的特性与 layui 完美结合,达到快速启动项目的目的。让开发更简单高效,C , | 8 J即使- = Y你不会前端layui1 W R O y p m O Q,也能轻松掌握使用。

JFinal-layui v1.4.2 新增XSS、CSRF防御和代码生成器,加强web安全和提升开发效率!在工作中发现,一些公司在给客户开发系统的时候,都很容易忽略了w5 v 3 { I ! w Jeb安全的内容,A | r - P U ! w或者根本不考虑web安全漏洞,所以这样开发出来的系. e ] j 0 统本身就是存在很大的安全f ` i a X 6 N b隐患,只要稍微有点技术的人员就能进行XSS攻击和CSRF跨站请求伪造!因为本人有过一段难忘的web安全漏洞修复的经历,所以把积累的一些经验应用到JFinal-layui中,让系统更加安全可靠!

v1.4.2更新内容详情:

一、XSS攻击防御

JFinal-layui主要是对XSS的存储型攻击进行防御,把用户输入的数据都进行XSS过! Q p K 5 & V k滤,避免对系统造成不良影响。利用J- + W aFInal的Handler来实现,重写Htt! 2 j MpServletRequestWrapper非常简单。

1、自定义Xs+ a !sHttpServletRequestWrapper类,重写getParameter:

/**
 * xss过滤处理
 * @author L | C;QinHaiLin
&nbf M o 1 p B [ n gsp;* @date&nbsO O R / P Gp;2020-02-1W M U [3
 *l g $ x ~ Z/
pw v Vublic class XssHttpServlg ] _ ] s S uetRequestWrapper extends HttpServletRequestWrapper{

&nbsf $ ? e m | i p;&nbsF ~ 6 C wp;  public XssHttpServletRequestWrapp2 q F } y - l q Cer(HttpServletRequest request) {
  &3 k ~ H ` 0nbsp;     super(request);
  / l T l p 0;  }
 
 Q 5 6 H | l U | `  /**
     * 重写并过滤getParameter方法
     */
    @Override
    public Strit U v { =ng getParameter(String namX # N r I g *e) {
  6 % [ = T ` 6 b t;      return getBasicC l { s 9 & q AHtmlandimage(suV 4 H gper.getP! ^ H U m ]arameter(name));
     &nr ` nbsp;&nbs? C x 5 $ - Up; 
  &% L E c # 0 2nbsp; }
     
    /**
 &nb$ r ,sp;   * 重写并过滤getParameterValues方法
     */
    @Override
    k O c r - %;pub` E # Blic&n& A e Y ( L Rbsp. - t x J P;String[] getParameterValues(String name) {
 &nbsb @ f U B 4p;&nbh a ! ? 3 9sp;     String[]&n. p C ? Z bbsp;values = super.getParameterValues(name);
        if&nbs; % l + A K wp;(null == values){
        h m k 1 d w x W;  &nb@ 7 v l J ) sp; return null;
 ? C R R b p 5 m w;&n| E w obsp;    &nf L d U d e } ebsp; }
        for (int i = 0; i < values.length0 $ 4; i++) {
 &nf | T # j ] 8 _bsp;   i - l , / [ ; ;     &nbs? S r Ip; values[i] = getBasicHtmlandimage(value@ Q E K I ( *s[i]);
 c # H e 6 I;&] = q s D 0 h }nbsp; &nR ) y 8bsp;    }
 &nb/ v b c $ s s A ?sp;      return&nbb | 0 @ T T Jsp;values;
    }
   &n~ w rbsp; 
    /**
     * 重写并过滤getPaY C xrameterMap方法
     */
    @Override
 q } * X   pu: ~ A l c +blG G % 6 eicR C } u & 0 N Map<String,String[]> getPars ^ 3ameterMap() {
Map<String,String[]> paraMap = super.getParameterMap();
       &nbsI 8 L ] bp;// 对于paraMap为空的直接return
      &nbsV K r c * a lp; if (null == paraMap || pa0 q d S xraMap.isEmpty()) {
            return&nb. { n t e 4 } usp;paraMap;
     A ) | a V / [;&nbsm V c Yp;  }
     &nbs_ i Q v g dp;  
  &nbsw K Op;    , | n //super.getPT ` s / @ 3 ( z DarameterMap()不y t O ^ | c允许任何修改,所以只能做深拷贝
  &nj q X E y f c bsp;  | f 6 b d ^ W   Map<String, String[]> p] K g % l _ q l *araMapCopy = new HashMap<String, String[]>();
        _ X % * i L E;//实际上putAll只对基本类型深拷贝有效,如果是自定义类型,则要找其他办法
  &n1 : 2 - m ! o n Cbsp; 9 1 [ ; f = r z D G t d i d O K R   paraMapCopy.putAll(paraMap);
    &n8 ] 8 t _ N F e 1bsp;   
 &nba I * i / , * Msp;&ni d Y v F ) Z *bsp;  m ( Q;&n_ Y dbsp;  fR y - M O s 4or (Map.Entry<String,&n) u M ) (bsp;St* S 8 @ 8 I ) t )ring[]> entry : q G -paraMapCopy.entrySet()) {
   7 6 * z ( r z K  &nbs% # C E t x t hp;&nbs# A _ Ip;     ST D x L { U ytring[] i # t * ; ? 4 W [;values &ns , . y ! ybsp; ] m G G 4 I x;  = entry.getValue();
     &nbs3 c V 5 ] { vp;      if (null == val? & 4ues) {
   &f 0 R L Enbsp;    &u O !nbsp;&{ O | 3nbsp;      continue;
 &nba z # Bsp;  l - b 8 J 9        }
&nb7 Q ~ #sp;         &n] g Gbsp; String[] newValues  = ne0 G 1 V Xw String[values.. V 4 } L ; + [length];
   ( 8 ] j Q s;      &nbsf 9 l S I i op;  for (int i = 0; i < values.length; i++) {
     k A 8 T;         c R ~ 8 4;  newValues[i] = C ( sgetBasicHtmlandimage(values[i]);
       &nbf | y S e Xsp;    }
 j G ! . K . $ # ,; &nbs! % ! . m T 1p;    &nl g 6 ] G T v % ibsp;    entry.setValue(newValues);
        }
   &nbse L z I ? q * Hp;   &nb^ f ] @ W * B 7sp;^ P ureturn par# l l A : @ +aMapCopy;
&nbsD 6 3p;   }
    
   u w * 5 c ; private static StK % qring getBasicHtmlandimage(String html)b h p i _ x B {
  h p ` f # Y , 6 }  if (html == null)
        rx A 6eturn&n| 0 e bsp;null;
    return| 1 G k H H J ~ {&nbsi Y 9 g 1 j - .p;Jso& u ^ o K a {up.cleM A } w p 7 aan(html, Whitelist.basicWithImages());
}
}

2、新建XssHandl] % ; t { C U Der拦截器:

/**
 * xsx u !s拦截j J x u
 * @author QinHaiL{ ) p s j cin
 *
&n} 6 J | 2 ^bsp;*/
public clas} s : } m {s XssHan6 ] 8 z z | Q k Edler extends HandlerB e ^ s - Y ^ N 8 {


// 排除的url,使用的target.startsWith匹配的
   private String excludePattern;
    
   /**
    * 忽略列表,使用正则排除url
    * @param&nbh p e H R ! Dsp;exclude
    */
   public XssHax ( ! u y sndler(String excludePattern) {
&s % unbsp;    &n8 K p t Pbsp;&] ? B g !nbsp;this.excludePattern/ I t w Z & ? : v # p N m= excludePattern;
 &nbs| ` U 7 Lp; }

@Oveq ] O ` * o ~ )rride
public void handle(String target,&nbs0 + ; x N { ) ?p;HttpServletRequest request, u m 4 / h B s b l;Htk g L w 1 i : D ;tpServleJ G Z d s , q M LtResponK ; w ise respox H H D e { S v anse,&nbsB ? ` | H d ^ mp;boolean[] isHandled) {

java.util.regex.Pattern&X _ V W y y anbsp;pattern = Pattern.compile(excludePattern);
//带.表2 W g示非action请求,忽略(其实不太严谨,如果是伪静态,比如.html会被错误地排除);b { ] /匹配excludePattern的,忽略
      &nbl , h 1 9 /sp;8 j F l Iif&nbsd { x T @ i 9 } Vp;(tr : Y rarget.indexOf(\".\") == -1 &: G $ l& !(!StriE o L N , / F l RngUtil.isBlank(excludePattern) &; t ^ f i& pattern.matcher(target).find() ) ){
      _ Y c L j o f ; o     request = new Xj 2 m GssHttpServletRequestWrapper(request);
   &4 ( Unbsp;   }
       
  &n) v 2 q } 2 U TbspB Y 5 l T v B 9;    next.handle(targe~ # X ! 6t, m T x K ) Q $ C;requeV = Vst, response, isHandled);
 8 l w 9 V r 9 u;   &ng ) S Z I ibsp;  
}

}

3、在MaG - X E k 2inConfig里面配置XssHandler拦截器,那么对XSS的存储型攻击就可以进行有效的防御了。

	/**
 * 配置全局处理器
 */
@Override
public void configHandler(Handlers me) {
/** 配置druid监控&nbn r k usp;**/
me.add(DruidKit.getDruidStatViewHandler())( i , ! , 1 v
// 路由处c z M K B s e
me.add(new CommonHandler());
// XL 5 * 4SS过滤
me.add(new XssHandler(\"^\\\\/portal/form/vi{ } ` ] q +ew.*\"));
}

二、CSRF跨站请求伪造防御

针对CSRF跨站请求伪造,JFinal-layui主要是对添加、修改的业务表单加入token验证机制,这样就可以解决重要业务操作的安= H X / D k全性。我们的拦截是全局验证拦截,在? t | R开发功能过程中就是顺手做的事2 @ o 9情,简单高效。

1、利用JFu 2 0 O 4 (inal0 v }的token机制,创建自己的TokenService:

/**
&e Q V T 0 K 0 ~ $nbsp;*&nR z Dbsp;token
 * @authc A v z ~ 0 $ Mor QinHaiLin
 * @date 2020-02-14
 */
public class&n( : . ? {bsp;TokenService&nb[ a a 7 o C Qsp;{

/**
 * 创建token
 *&nbY M B 6 K - / msp;@param c
 */
public vo( n #id createToken(Controller&nby @ ~ ` Vsp;o B P : { t @ M Cc){
TokenManager.createToken(c, Const.^ = s { T A 5 9 zDEFAULT_TOKEN_NAME, Const.DEM K QFAULT_SECx bONDS_OF_TOKEN_TIME_OUT);
}

/**
 * 验证tokD T j t A len
 * @param c
 */
public boolean validateToken(Co% 8 ! c 6ntroller c){
return TokenManager.validateToken(c, Const.DEFAULT_TOKEN_NAu . b ] ~ME);
}
}

2、再创建TokenInterceptor的拦截器进行全局拦截验证:

/**
 * L Q d /token拦截器
 * @author QC v PinHaiLin
&n$ ~ u nbsp;* @date ? , ~ I G 9 q;2020-02-1W g Y : )3
 */
public class TokenInt[ 0 $ N t erceptor&nbN B @ N w x 2 psp;implements Interceptor {

@Inject
TokenService tokenServ3 J ^ Q , W sice;

@Override
public$ d 1 Y b void intercept(Invocation&nb( } r asp;in9 ; = 3 ( P x f Dv) {
Controller Q 2 f O B T v F $;c=inv.getController();
String methName=inv.getMethod().getName();

//给默认的添加、修改方法添加tokeJ n * Dn
iw f D Y ` , d s Sf(methName.equals(\"add\")||methName.equals(\"e] ; Fdit\")){
tokenService.createToken(c);
}

//验证token
if(methName.equals(\"save\")|$ % M|methName.equals(\"update\")){
boolean b=tokenService.validateToken(c);
if(!b){
boolean isAjax=\"XMLHttpRequest\".equalsIgnoreCase(c.getHeader(\"X-X # ; O D s ;Requested-With\"));
if(isAjax){
c.renderJson(Ret.fa~ a 7 A ` ~ | Zil(\"mv 2 R l 4sg\", \"token验证不通过,请刷新页面\"));
}else{
c.Q ~ ? s vsetAttr(\"msg\", \"token验证不通j f D % Q G过\");
c.renderError(403);
}
ree R 2 hturn;
}
//添加修改成功后,返回对的页{ ^ p q ? K J E面,此处是解决业务验证不通过的情况,如:添加用s _ W & & E o S户时,如果存在用户编号,那么需要重新填写,此时就要重新赋值新的token
tt ` F z w ;okenService.createToken(c);
}
inv.invoke();
}

}

3、在MainConfig配置成全局拦截器即可:

/**
 * 配置全局拦截器
 */
@Override
public void 0 8 + K v U S;configInterceptor(Interceptors me) {
me.addGlobalActionInterceptor(new&nbsm j Lp;SessionInViep B S / n L ( LwInterceptor());
me.addGlobalActionInterceptor(new SesS ) / q +si# P ] a X H AonInterceptor());
me.addGlobalActionInterceptor(new&nbs$ u ( 0 C tp;ExceptionInterceptor());
//表单token验证拦截器1 N U P | =
me.addGlobc W 6 ! % / ; v salActionInterceptor(new TokenInter { | T { ! L 0rceptor()) p y;
mQ . c R L &e.addGloW R R l N |balActionInterceptor(new LoggerInterceptor());
}

4、在添加修改的操作表单输出token:#(tokel & D } V bn)

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

三、代码生成器

为满足广大用户1 k 0 X U m {要求,还是决定把代码生成器集成进来,那么有了这一神器,u s s x l就可以把那些繁琐重复的开发工作交给代码器了,一键多表生成代码文件,页面操作简单,直接生成代码文件到项目当中,刷新重启F S G $ }项目即可。

1、代码生成器操作页面,选择需要的表,可多选,点击选择按钮即可:

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

2、点击生成代码,这是预览代码,还没有真正创建代码文件,点击下载代码才是最终在项目中创建:

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

3、点击下载代码,创建文件:

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

4、刷新项目,就能在预先设置的package里面创建对应的Java文件了,html目录也是按照相应规4 4 D h 0 q则创建对应的目录:

java文件: html文件:

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

5、此时代码文件已经创J - m x M d 3 J P建好了,还需要最关键的一步,那就是把_MappingKit.java里面在数据库表映射关系配置到主配置文件中:

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

6、最后就是启动项目,H o l 8 R S A r s配置菜单权限即可访问e S ( 8 o了。

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

【开源资讯】JFinal-layui v1.4.2 来袭,XSS、CSRF防御、代码器

上一篇

和珅被判死刑,本想用乾隆留的遗诏保命,打开后笑不出来

下一篇

硬核!逛了4年Github 、一口气把我收藏 Java 开源项目分享给你

评论已经被关闭。

插入图片
返回顶部