解决layui的table组件data-content未转义导致的注⼊问题。
本⽂更新不及时,建议到原⽂地址浏览:。
layui是⼀套⾮常不错的后台管理系统UI框架,其简约并具有系统感的设计赢得了许多开发者的青睐。不过我在使⽤layui的动态表格组件时遇到了⼀个问题,当数据中存在未转义的数据时,表格在渲染时会备份⼀个数据在dom属性上,⽽此数据未进⾏html转义导致存在注⼊攻击问题。我通过源码阅读,了解到了为什么此问题的原因,并完美修复这个问题。下⾯将进⾏详细介绍。
⼀、问题重现
并不是所有情况都会有这个问题,只有当你在为某⼀个字段设置了templet模板。不管是⼀个⽅法,还是⼀个模板语法,layui才会在此单元表格上新增⼀个data-content属性。⽽此时,如果你的数据⼜恰巧包含了html能解析的内容,⽐如:当你有⼀份形如下⾯的数据要显⽰到table组件⾥⾯时,由于未对data-content属性进⾏转义赋值,导致你的页⾯可能与预期展⽰不⼀样:
var data =[
{id:1, name:"Tom\"> <b οnclick=\"alert(66)\">呵呵</b>"},
{id:2, name:"Bob\"> <b οnclick=\"alert('你完了')\">完蛋了</b>"}
];layui下载
把这份数据通过设定templet渲染到table组件。得到下⾯的效果:
不仅仅是被攻击者达到了意图,⽽且点击它们还会弹出提⽰信息。再来看⼀看dom结构被这个数据搞成了什么样:
可以看到,由于data-content没有转义,导致界⾯dom结构凌乱,并且丢失了前端正常的功能。标记1处就是因为没有转义,数据⾥的html 被应⽤到了dom结构⾥,尽管我们在templet⾥进⾏了转义使得标记2正常显⽰数据,但依然没能让data-content进⾏转义。⽽如果这是⼀个⼗分恶意的攻击,那么这个⽹站应该在这⾥就被攻破了。我们当然不能允许这样的事情发⽣。毕竟要恰饭的。
⼆、修复问题
修复问题的办法有好⼏种或者更多,这⾥推荐⼏个⽐较简单的解决⽅案。
1、后端修复
后端在数据库中将数据查询出来后,就对有些敏感字段先进⾏⼀下html转义,让前端接收到的数据已经是⼀个⽆需担⼼注⼊的安全字符串。那么这样就可以放⼼使⽤了。要在后端进⾏转义,下⾯提供⼀个⽰例代码:
String badStr ="<script>alert(66)</script>"
// 使⽤ Spring 提供的转换⼯具
String safeStr = HtmlUtils.htmlEscape(badStr);
// 现在,就可以放⼼的使⽤ safeStr 传递给前端了。
2、前端修改table组件代码
如果后端代码被多处使⽤,⽽有些"端"并不需要转换,只针对部分“端”才需要,那如果后端修复不是很⽅便的话,前端就不得不⾃⾏修复了。在前⾯也了解到,即便我们在templet⾥⾯使⽤了转义输出,也依然阻⽌不了data-content的发⽣。看来data-content的赋值是我们控制不了的了。
所以,不妨直接打开table组件代码,搜索data-content字段,直接定位这个赋值代码。下⾯代码截取⾃layui项⽬table组件[提交版本号5904e5b1344efa661b53f1cbd2a5d0e5b12ea4ef]的部分代码:
that.eachCols(function(i3, item3){
var field = item3.field || i3
,key = options.index +'-'+ item3.key
,content = item1[field];
if(content === undefined || content ===null) content ='';
lGroup)return;
//td内容
var td =['<td data-field="'+ field +'" data-key="'+ key +'" '+function(){//追加各种属性
var attr =[];
if(item3.edit) attr.push('data-edit="'+ item3.edit +'"');//是否允许单元格编辑
if(item3.align) attr.push('align="'+ item3.align +'"');//对齐⽅式
plet) attr.push('data-content="'+ content +'"');//⾃定义模板
lbar) attr.push('data-off="true"');//⾏⼯具列关闭单元格事件
if(item3.event) attr.push('lay-event="'+ item3.event +'"');//⾃定义事件
if(item3.style) attr.push('');//⾃定义样式
if(item3.minWidth) attr.push('data-minwidth="'+ item3.minWidth +'"');//单元格最⼩宽度
return attr.join(' ');
}()+' class="'+function(){//追加样式
上述代码中,第14⾏代码处可以看到,这⾥直接对data-content进⾏赋值,完全没有进⾏转义的⾏为。所以,我们现在只需要加上转义的代码就好了:
// 原来的代码
plet) attr.push('data-content="'+ content +'"');//⾃定义模板
// 修改为:
plet) attr.push('data-content="'+laytpl("{{=d.t}}").render({t:content})+'"');//⾃定义模板
可以看到,上述代码中,借助了laytpl模板引擎,⾮常⽅便的就实现了数据转义后赋值到data-content⾥⾯,这样,就不会再出现注⼊攻击了。修改后,我们看看现在的效果以及dom结构:
现在不论是界⾯显⽰,还是dom结构,都已经显⽰正常。data-content也进⾏了转义显⽰,没有任何问题。
三、注意
上述在前端修复的⽅案,其修改的代码是layui的源代码,并⾮你下载的layui代码,但你可以修改好后,将修改好了的table组件代码覆盖到你下载的layui对应的组件,也可以有效果。你也可以直接修改下载的源代码。不过下载的代码是经过编译缩⼩的,所有字段都变成了单个字母不便于识别,修改时要⼩⼼,准位置和代码,使⽤同样的⽅式进⾏修复,不过要注意,这时laytpl可能就是另⼀个字母变量了。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。