发表于: 2018-01-30 18:34:49

1 719


今天的内容:任务五验收

大家好,我是IT修真院上海分院第5期的学员卢炳伸,一枚正直纯洁善良的JAVA程序员。

在一些web应用中,有些资源的访问是受到限制的,需要用户注册登录验证后才能访问。那作为开发者的我们,如何去判断用户是否已经登录,以及登录信息是否有效呢?答曰:在SSM框架中,可以使用cookie技术。对于受到保护的url,我们通过设置拦截器进行保护,每次用户尝试登录时,通过拦截器判断用户cookie的合法性,合格才可放行。

在本次示例中,为了提高安全性,采取session绑定cookie的方式实现用户验证。首先,我们了解一下什么是session,什么是cookie。这两者在本质上并没有什么区别,session是服务器端一个输出型的cookie,服务器响应浏览器的request,并为其生成独占性的session对象。如果用户浏览器没有禁止cookie,就会发送回一个名为JSESSIONID的cookie,这个cookie保存了该session的唯一标识(id)。而cookie是保存在用户浏览器里的,我们平时清理浏览器数据的时候也能看见cookie这个玩意儿。

每次用户成功登陆后,会产生一个cookie,这个cookie的内容一般是经过加密的,而且不会保存用户密码等敏感信息。每次提交cookie时,会在web应用的拦截器处做一个信息校核,与登陆时服务器端session保存的信息做一个比对,最基本的例如:

服务器端Session Token的添加

用户提交Cookie时的校核:

可以看到,我这里对密码进行了MD5加盐加密,是单向的,理论上是不可逆的(其实还是可以被暴力破解),而token数通过DES加密的,它的加密方式是双向的,在加密前,我采用了最普通的一些数据处理:private String byteArrToHexStr(byte[] arrB){

        int iLen = arrB.length;

        // 每个byte(8位)用两个(16进制)字符才能表示,所以字符串的长度是数组长度的两倍

        StringBuilder sb = new StringBuilder(iLen * 2);

        for (byte anArrB : arrB) {

            int intTmp = anArrB;

            while (intTmp < 0) {//把负数转化为正数

                intTmp = intTmp + 256;

            }

            if (intTmp < 16) {//小于0F的数需要在前面补0

                sb.append("0");

            }

            sb.append(Integer.toString(intTmp, 16));

        }

        return sb.toString();

    }


    // 将表示16进制值的字符串转换为byte数组,和public static String byteArrToHexStr(byte[] arrB)

    private byte[] hexStrToByteArr(String strIn){

        byte[] arrB = strIn.getBytes();

        int iLen = arrB.length;

        // 两个(16进制)字符表示一个字节(8位),所以字节数组长度是字符串长度除以2

        byte[] arrOut =new byte[iLen/2];

        for (int i = 0; i < iLen; i = i+2){

            String strTmp = new String(arrB,i,2);

            arrOut[i/2] = (byte) Integer.parseInt(strTmp,16);

        }

        return arrOut;

    }


可以看到,DES算法是将64位的明文输入块,变为了64位的密文输出块。然而,今天我想表达的重点并不是DES的原理,而是如何利用DES这个工具实现对XSS攻击的防御。先简单了解下XSS(跨站脚本攻击Cross Site Scripting)的一种方式,Session挟持:

在本例中,我们通过的是DES解密Cookie中的token内容,然后和登录时Session中添加的token内容做一个比对,如果相同,则放行。但试想一下,如果有黑客成功抓包,获取了用户的Cookie信息,然后通过某些方式(比如研究应用程序的Session超时机制和心跳包机制),就可以在用户使用完后继续使用这个Session!然后黑客就可以利用这个Cookie,骗过web应用的拦截器,直接跳过登录系统登录!!!

可以看到,这个安全漏洞是极其致命的!如果用户退出时没有注销用户信息,服务器端的token数据没有被销毁,万一被黑客抓包,那么这个账号基本上就彻底落到了黑客的手里!哪怕是改密码都没有用,因为cookie的登录是不需要密码验证的!

那怎么解决这个问题呢?或许注销机制是一个解决方案,但用户的行为是极难受到控制的,而且问题远不止如此,哪怕你注销了,依旧存在有一个安全漏洞。这种方法,可能是真正意义上的session挟持:

在用户持有合法cookie,尝试进行登录时,黑客可以覆盖此次的token内容为一个无效值,然后服务器会 认为用户身份为未登录,于是会要求用户再次登陆。用户再次登陆之后,他获得新的Session Token,而由于应用程序的机制,之前的Session Token并没有失效,这样服务器上的session就存在有两个有效的token了。而接下来,哪怕假设用户很注意安全,他有退 出应用程序的使用习惯,他销毁了他的token,但是仍然有一个token被黑客掌握。这种方法的狠毒在于,即使用户意识到Cookie被窃取,但如果web应用的设计有问题,即使他修改密码,也不能控制服务器注销掉被黑客掌握的会话!相当于,用户的Session永远被黑客掌握了, 他也永远不知道这个Session Token是多少。

关于这个安全漏洞,的确很难应对,除非采用绑定ip和token过期的机制,但这样子可能会降低用户的体验。除了事前控制,还可以进行设计一套事后补救的措施,使得用户在修改密码后,原来被挟持的session就失效:    

这样子,黑客原来掌握的session就彻底失效了,我们甚至可以设计一套机制,进行反击!(这里的XSSException是自定义异常,可以被Spring统一的异常拦截器所拦截,然后进行特定性处理,比如对比前后登录IP信息,如有异常拉黑名单什么的)

在token里面嵌入时间戳,然后和数据库里面的登录时间戳进行比较,这个方法虽然可以解决一部分问题,但是它的缺陷也是很明显的:用户本人的多开操作(比如拿手机和电脑同时访问)也会导致这个异常。不过对于一些安全要求较高的网站,依然可以采取类似此类方法,降低被黑客挟持的危险。虽然对于大型的网站,他们自己就有更好的安全工具,但这种思维的培养,对我这个新手后端工程师来说,依旧是大受裨益的。

最后打下广告,给我们培训机构的:

IT修真院是一个免费的线上IT技术学习平台。

每个职业以15个左右的task为初学者提供更快速高效的学习方式;

所有task均是从真实项目中提炼出来的技能点

强调实战演练+自学优先+师兄辅导的学习方式

严格的日报体系,欢乐的交流讨论学习气氛,更有无数师兄师姐帮你解疑

点击官网!

http://www.jnshu.com/login/1/17064795

嗯,老大很帅!



返回列表 返回列表
评论

    分享到