JFinal mass assignment

demo下载地址:

http://note.youdao.com/noteshare?id=bed3a7acfabaaf574a226901ec703867


        /**
	 * save 与 update 的业务逻辑在实际应用中也应该放在 serivce 之中,
	 * 并要对数据进正确性进行验证,在此仅为了偷懒
	 */
	@Before(BlogValidator.class)
	public void save() {
		getBean(Blog.class).save();//此方法不安全,请参考 update方法
		redirect("/blog");
	}
	/**
	 * save 与 update 的业务逻辑在实际应用中也应该放在 serivce 之中,
	 * 并要对数据进正确性进行验证,在此仅为了偷懒
	 */
	@Before(BlogValidator.class)
	public void update() {
		//注: 在Blog表新增money字段类型为number并且可为空
		//原实例方法
		//getBean(Blog.class).update();
		//redirect("/blog");
		
		Blog blog=null;
		
		//一,新方法 Bean方式
		blog = getBean(Blog.class);// 原方法 不安全
		//// 方案一:保留法
		blog=getBean(Blog.class,new String[]{"id","title","content"});
		//// 方案二:排除法
		// blog=getBean(Blog.class, ModelFilterType.REFUSE, "Money");
		//// 方案三:过滤器
		//String acceptStrs = ",id,title,content,", //只接受字段
		//			refuseStrs = ",content,money,";//拒绝接受字段
		// blog=getBean(Blog.class, new ModelFilter(){
		// @Override
		// public boolean accept(String paraName) {
		// return acceptStrs.contains(","+paraName+",");//可以使用正则表达式
		// }
		// @Override
		// public boolean refuse(String paraName) {
		// return refuseStrs.contains(","+paraName+",");//可以使用正则表达式
		// }
		// });
		//二,新方法 Model方式
		//blog = getModel(Blog.class);// 原方法 不安全
		//// 方案一:保留法
		// blog=getModel(Blog.class,new String[]{"id","title","content"});
		//// 方案二:排除法
		// blog=getModel(Blog.class, ModelFilterType.REFUSE, "Money");
		//// 方案三:过滤器
		//String acceptStrs = ",id,title,content,", //只接受字段
		//			refuseStrs = ",content,money,";//拒绝接受字段
		// blog=getModel(Blog.class, new ModelFilter(){
		// @Override
		// public boolean accept(String paraName) {
		// return acceptStrs.contains(","+paraName+",");//可以使用正则表达式
		// }
		// @Override
		// public boolean refuse(String paraName) {
		// return refuseStrs.contains(","+paraName+",");//可以使用正则表达式
		// }
		// });

		blog.update();

		redirect("/blog");
		
	}

注解方式启动项目


/**
	 * 配置路由
	 */
	public void configRoute(Routes me) {
		
		//me.add("/", IndexController.class, "/index");	// 第三个参数为该Controller的视图存放路径
		//me.add("/blog", BlogController.class);			// 第三个参数省略时默认与第一个参数值相同,在此即为 "/blog"
	
		//-----------alotuser--------------//
		JRoutes jme=new JRoutes(me);
		
		jme.adds("com.demo");//@方式一, 加载指定包下控制类
		//me.scan("", JType.SECOND, "com.demo");//方式二,区分级别
	}
	/**
	 * 配置插件
	 */
	public void configPlugin(Plugins me) {
		// 配置 druid 数据库连接池插件
		DruidPlugin druidPlugin = new DruidPlugin(PropKit.get("jdbcUrl"), PropKit.get("user"), PropKit.get("password").trim());
		me.add(druidPlugin);
		//---------alotuser-配置ActiveRecord插件----------------------------------------------//
		JActiveRecordPlugin arp = new JActiveRecordPlugin(druidPlugin);
		arp.setDialect(new OracleDialect());//设置数据库方言
		arp.setContainerFactory(new CaseInsensitiveContainerFactory());//忽略大小写
		arp.setShowSql(true);
		// 所有映射在 MappingKit 中自动化搞定
		
		//_MappingKit.mapping(arp);
		//------------alotuser-----------------//
		arp.addMapping("com.demo");//@加载指定包下实体类
		me.add(arp);
	}


评论区

要输就输给追求

2018-10-23 18:16

看得一脸懵逼

alotuser

2018-10-23 18:43

@要输就输给追求 试一下在Demo修改页面form表单里加入blog.money隐藏域并设置个数值,再提交,看看数据库有没有变化。比如:Demo中创建blog像开通VIP会员,其中money字段是需要用户支付的金额,如果用户在开通会员并注入money值为0,那么最后用户可以免费开通会员了。这样可以理解吧

JFinal

2018-10-23 19:43

@alotuser 这个问题在 6 年半以前就有人提到过,但对方提出来的时候 jfinal 就已经有提供 API 来快捷解决问题, 6 年半以前的贴子在这里:
https://www.oschina.net/question/260040_46570

这个问题学名叫:mass assignment, 楼主能看到这个现象证明极其细心,在 IT 这行很有发展潜力啊

简单说,在 getModel(...) 以后,通过 Model.keep(....) 即可指定哪些字段是保留的,哪些是要删除的,例如更新用户信息时如果用到了 User ,那么:
getModel(User.class).keep("nickName", "email").update();
就只会更新指定的字段

无论恶意用户如何在表单中制造新的字段都不可能形成威胁。 这个问题其实对传统的 web 框架也有同样的问题,除非为接收表单单独做一个只存在部分字段的 setter 方法,否则那些没在表单中的字段也可以被注入

JFinal

2018-10-23 19:44

补充一下,jfinal demo 仅为了展现最简洁的 demo,所以对 getModel(...) 没有添加:
blog.keep("id", "title", "content");

JFinal

2018-10-23 19:49

再补充一下, jfinal 的 Model 中还预备了一个回调方法叫 public void filter(...),只要你的 model 中覆盖掉这个方法,就会被回调,如果希望有更高的安全性,避免其他开发者没有使用 Model.keep(...) 从而造成问题,还可以像下面这样来做:

public class User extends Model {
protected void filter(int filterBy) {
// 这里使用 keep 或者 remove 过滤掉一些不希望被操作的对象
// 在需要对这些字段进行操作时,使用别的方式来做,例如Db.save()
}
}

alotuser

2018-10-23 20:58

@JFinal 您好,我比较喜欢jfinal框架。我的想法是从源头杜绝,性能相对来说好一些

JFinal

2018-10-23 21:06

@alotuser 源头不好杜绝,假定你的 account 这张表有个字段叫 money,然后你的 Model 通常也会有 setMoney(int) 方法,这个 setMoney(int) 在正常使用情况下用于合理的需求,例如更新 money 值的时候

但为了合理需求而创建的 setMoney(...) 方法也会被非法利用,恶意用户可以人为制造带有 money 字段的 post 请求,客户端的这个恶意操作是无法消除掉的

alotuser

2018-10-23 21:30

@JFinal 我的意思是说在set方法前通过条件过滤,说白了,model的remove方法是接受post参数然后通过条件删除,这种特殊情况。我想说的是在model形成前通过条件先过滤,可以提高一下性能。

JFinal

2018-10-23 23:47

@alotuser 具体怎么做呢? 能否在贴子里头补充点示例性的代码?

我在直觉上感觉这个没法处理,因为 setter 方法也是要用于正当功能需求的,如果过滤的话,也就影响正当功能了

热门反馈

扫码入社