前言
学过编程的孩纸,都知道注册/登录是最基础的功能了。但是却不意味着是最简单的。这里的讨论范围都是基于网页应用的登录功能,由于受Http协议的限制,对于保护用户的账号安全,不同的网站有不同的方法(奇技淫巧)实现。
基础知识
- HTTP
基本上所有的网站登录方式都是通过该协议进行的,这是一种请求/响应式的协议。 - Fidder
HTTP网络抓包工具,可以清晰地看出每条协议的请求和响应。 - Postman
chrome的模拟请求插件,由于安全性考虑,默认是不发送cookie,需要配置。 - RSA加密
一种比较普遍的非对称加密算法,可以对用户密码进行加密之后在网络协议中传输,以防被黑客截包也难以破解。 - HTTPS
是HTTP的安全版,即HTTP下加入SSL层,加密原理也是RSA,提高了明文传输的安全性。 - 验证码
验证码的历史、奇葩进化史(直指12306),我就不絮叨了。是一种防止机器爆破的手段。 - cookie
一般要实现”记住登录状态”都需要这玩意,cookie泄露会给黑客平添许多机会。 - httpOnly
为了减少JS任意操纵cookie的权利。规定了设置为httpOnly的cookie,JS将无法获取。 - session
意指”会话”,在一次会话中,session取值不变。session的实现依赖cookie。 - EditThisCookie
chrome的cookie操纵插件,好用到不行。
下面直接看各式网站的例子。
37WAN(http://www.37.com )
- 简述:第一个开刀的将是我们公司的平台网站,部分研究成果来源于@daxingxing。
登录请求:
请求地址:https://my.37.com/api/login.php
请求方式:GET(跨越请求)
请求参数:123456789101112{"callback": "jQuery18304817038912751921_1471407128764", //跨域请求必须"action": "login", //登录路由"login_account": "xiaorui2016", //用户名"password": "Y3NvRmFIZll4eHhyekU1VngyMDE2cWU=", //密码加密规则如下"ajax": 0,"remember_me": 1, //是否记住登录状态"save_state": 1,"ltype": 1,"s": 1 //登录来源,去掉该参数会提示必须从37.com入口登录"_": 1471407134871 //登录时间戳}响应格式:
12345{"code": -7, //状态码,0是正确,其余都是错误码"data":{}, //响应数据,登录成功会带有用户信息"msg":"" //提示语}登录密码加密规则
先来看一组例子:
源:xxxx2016
加密:base64_encode( csoFaHfYxxx
rzE5Vx2016
qe )
源:2015cccc
加密:base64_encode( 0hqAjYOg201
pqROH5cccc
58 )
源:ccccccccccc2016123000
加密:base64_encode( vmZUFVzJccc
vTB0Cccccccc2015123000
16 )遗憾的是37平台的密码在网络传输的时候,并没有使用RSA非对称加密,加密规则如下:
8位随机字母+前3位密码+5位随机字母+从第4开始截取至最后一位密码+两位随机字母 > base64加密以上结果
加密的详细代码过程sq.login2015.js,有兴趣同学可以down来学习。关键cookie
name:ispass_37wan_com
value:6ace1125|-1|5605d21a6ae2c7128e72cbab2axxxxxx|1
说明:身份验证凭据,httpOnly,可以确定该cookie内携带了密码信息name:passport_37wan_com
value:704499552|xiaorui2016|1471421091000|e893376b48c81db281db07ed92xxxxxx
说明:登录状态,非httpOnly,登录成功状态下携带用户信息,否则为”logout”。以上两个cookie缺一不可,如果任意删掉其一,登录状态会被重置为登出。换言之,如果这两个cookie泄露了,黑客就可以不需要密码就可以登录你的账号。
补充
- 巧妙通过两个cookie的结合实现记住用户登录状态,提高破解难度和安全度。
- 如果使用Postman疯狂请求登录URl,大概20次之后,就要输入验证码才可以继续请求登录。再过一个小时,该限制会失效,可以再次疯狂请求20次。
- 删掉
passport_37wan_com
,刷新之后会直接重置到登出状态。如果删掉ispass_37wan_com
,会出现一个死亡延迟的现象,需要刷新两次才会被重置到登出状态。 - 重置密码的部分存在猫腻,该网络请求的密码居然是明文传输,令人堪忧!其次,需要输入密码二次确认(比如绑定邮箱、安全问题等操作),同样也是密码明文传输。 个人认为明文传输至少也要是Https协议,然而并没有!
知乎(https://www.zhihu.com)
简述:知乎网站的安全意识是极高的,除了一言不合就输入验证码之外。还做了应付xsrf攻击和防止爬取关系链等一系列完善的措施。更了不起的是整站都是启用了https(包含所有CDN节点),能够看出该站点在竭尽所能地保护用户信息安全。部分灵感来自于@YYChildren
登录:
请求地址:https://www.zhihu.com/login/email
请求方式:POST
请求头:1234{"X-Xsrftoken": a9044561281b58d0466ea768ed28479c"Cookie": _xsrf=a9044561281b58d0466ea768ed28479c;}请求参数:
1234567{"_xsrf": a9044561281b58d0466ea768ed28479c //充当会话ID"password": xiaorui2016 //密码明文"captcha": xvek //验证码"remember_me": true //记住登录"email": xiaorui@126.com //用户名}响应格式:
123456{"r": 0, //请求结果,0表示无状态,就是成功的意思。1表示错误"errcode": 1991829, //当r=1时,附带错误码信息"data": {} //数据"msg": "登录成功" //提示语}关于登录请求
显然看到知乎登录请求比较特殊的地方:
第一,密码是明文传输的,得益于整站覆盖了https
第二,XSRF防御
简单说一下XSRF
攻击概念:攻击者盗用了你的身份,以你的名义发送恶意请求。一般通过服务端进行XSRF
防御,服务端的XSRF
方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。
比如知乎这里做法就是:所有表单都包含同一个伪随机值,这个随机值在cookie里面也保存一份。提交表单的时候做检验。这样做是因为攻击者不能获得第三方的Cookie(理论上),所以也就无法进行XSRF攻击了。如果你想了解更多关于CSRF/XSRF的内容,可以参考以下链接,同时一般框架Yii、larval等也有CSRF的相关内容,你可以深入源代码了解哦!
浅谈CSRF攻击方式:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html第三,验证码
知乎登录是必定需要填写验证码,而且验证码的形式也是随机出现的,大大增加机器爆破的难度,以下是我看到的两个不同形式的验证:
关键cookie
name:z_c0
value:Mi4wQUFCQThnSTFBQUFBY0VCT……|1473130391|5X094ceb64ce01ed37f31009e24308bd64eb6ede
说明:身份验证凭据,httpOnly,有三部分组成(用户身份token,登录时间,加密校验sign),拥有该cookie可以记住登录状态,虽然只有一个cookie,但是破解难度极高。每次请求都会得到新的token,旧的token会马上过期。换言之,如果无法知道加密算法几乎无法伪造cookie登录。而破解加密算法需要基于大量的样本,知乎关于防范多次注册/反复修改密码/找回密码等都有做处理,所以很难展开大量实验。补充
- 由于知乎自身定位和面向用户群体的原因,使得注册必须基于电话短信验证成为可能。在保证了用户真实性和可靠性的同时,也增强了网站安全性。
- 另外关于如何防止水军,保证原创内容的健康良好地生长。知乎也有很多设计细节,有兴趣地同学可以拓展研究。
- 修改密码方面,知乎会记录用户以前用过的所有密码,重置密码是不可以设置历史密码的。当然重置密码的请求也是明文的。
- 关于知乎站点研究并不是很透彻,源于手上账号样本不多。