http://blog.csdn.net/newjueqi/article/details/44062849
在很多app中,都需要用户的登录操作。登录,就需要用到用户名和密码。为了安全起见,暴露明文密码的次数越少越好。怎么能最大程度避免泄露用户的密码呢?在登录后,app后端怎么去验证和维持用户的登录状态呢?在本文中,给出了一套用户登录的解决方案,以供大家参考。
1. 保证登录的安全性,最起码要使用https协议
避免信息的泄露,最简单的方案是所有涉及到安全性的api请求,都必须要使用https协议。
HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议
它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换,简单来说它是HTTP的安全版。它是由Netscape开发并内置于其浏览器中,用于对数据进行压缩和解压操作,并返回网络上传送回的结果。HTTPS实际上应用了Netscape的安 全全套接字层(SSL)作为HTTP应用层的子层。
http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
注意了,https协议需要到ca申请证书,一般免费证书很少,需要交费。
我们可以看看所有大型网站,例如京东,淘宝,支付宝,涉及到登录和支付的页面,url都是以https开头,这就意味着,这次通讯是使用https。开放平台的api,例如新浪微博,腾讯等,api请求都是以https开头的。https是业界常用的保证安全性的协议。
因此,涉及安全问题的api,都应该使用https协议。虽然,https为了保证安全性,在效率上是比http协议低。
2. 基本的用户登录方案
在传统的web网站中,可以使用cookie+session来实现用户的登录维护,那么在app后端,可以怎么实现呢?
在app后端,怎么避免每次验证用户身份都需要传输用户名和密码呢?
一个生活的模型就是:
假设服务器是个房间,里面有个房间管理员,房间上的门有把锁,这把锁有两种打开方式:
1. 输入了这把锁上注册的用户名和密码,就能打开
2. 用房间管理员提供的钥匙打开
a.当第一次使用用户名和密码打开了这把锁后,进入房间,找到房间管理员,让他提供一把钥匙。
b.那以后每次需要进入这个房间,就用这把钥匙就行了,不用担心旁边有人偷看到自己的用户名和密码.
c.决定有一段时间不进入这个房间,又怕钥匙被偷,就进入房间里,把钥匙还给管理员,让管理员把钥匙毁灭
a就是登录的操作,b就是验证身份的操作,c就是退出登录的操作.
理论版的描述如下:
(1) 服务器接收到app发送的用户名和密码后,验证用户名和密码是否正确。
如果错误则返回错误信息。
如果验证正确,生成一个随机的不重复的token字符串(例如"daf32da456hfdh"),在redis或memcache中维护一个映视表,建立token字符串和用户信息的对应关系表,例如,把token字符串"daf32da456hfdh"和用户id"5"对应起来。
(2) 服务器把token字符串返回给app,app把这个token字符串保存起来,作为登录的验证。
(3) 当需要验证用户身份的操作时,必须要把token字符串传给服务器验证身份。
例如,api "test.com/user/update"是更新用户的信息,必须要验证用户的身份.当调用api "test.com/user/update"时,把token字符串"daf32da456hfdh"放在url上,变成"test.com/user/update?token=daf32da456hfdh" .
当服务器接收到这个api请求,知道要验证用户身份的,于是,就把参数中token的值"daf32da456hfdh"取出来,在(1)中建立的token字符串和用户信息的对应关系表查找,如果发现没这个token值的,则返回验证失败的信息。如果发现有这个token值,则获取这个用户的信息,进行相关的更新操作。
(4) 当用户退出登录时,需要通过调用api,让服务器把这个用户对于的token字符串删除.
例如,api "test.com/user/logout"是退出登录的api,也要验证用户身份, 则调用"test.com/user/logout?token=daf32da456hfdh" 。当服务器接到退出登录的api请求时,在(1)中建立的token字符串和用户信息的对应关系表查找token字符串,把token和用户信息都删除即可。
注意:这个方案并不是十分安全,这个身份验证是依赖于token字符串。如果用户泄漏了自己的url, 那很大程度上token也被别人泄漏了,就相当于钥匙被人复制了一份。在下篇的通讯安全中,会描述一个防止token在通讯中泄漏的方案。
=======================
https://segmentfault.com/q/1010000005775099
从根源上来讲,防止恶意攻击就需要验证手机号才能注册
首先你要明确,Token
是用于登录后验证身份的,所以一开始就否决了你期待用它来做防恶意注册,这两者完全不搭嘎。
其次,要说Token
与Session
有什么区别,那区别就在于Token
更具有定制型,因为它是由你实现的,就能干很多Session
不方便干的事情,比如更好的做设备认证,更方便的控制有效期,更好的跨平台性……最重要的,HTTP协议本身定义就是无状态的,而Cookie
这种东西的存在无疑有损无状态这个定义,所以几乎所有的接口都拒绝使用Cookie
,弃了Cookie
,那Token
自然成了验证的首选。
最后,Token
的安全性着重于其不会被破解,不会被篡改,而不在于它传输时会不会被截取造成中间者攻击。截取的防护应该是由你加强传输过程中的安全性来实现的,比如增加参数签名,或者直接上HTTPS。
===============================================
http://blog.majiawei.com/2016/06/18/api-auth/
生成签名
使用分配好的token + 请求URL + 时间戳 + 随机字符串 做混淆得到一个字符串。这里说明下为什么要加一个时间戳,是为了确保本次API请求的URL只能在一定的时间限定范围内被使用,防止被第三方非法重复调用的问题。最终构成的请求URL可能长这样https://api.mjw.com/post/list?uid=xxtimestamp=1425888757&sign=xxxx
http://keeganlee.me/post/architecture/20160107
安全机制的设计
现在,大部分App的接口都采用RESTful架构,RESTFul最重要的一个设计原则就是,客户端与服务器的交互在请求之间是无状态的,也就是说,当涉及到用户状态时,每次请求都要带上身份验证信息。实现上,大部分都采用token的认证方式,一般流程是:
- 用户用密码登录成功后,服务器返回token给客户端;
- 客户端将token保存在本地,发起后续的相关请求时,将token发回给服务器;
- 服务器检查token的有效性,有效则返回数据,若无效,分两种情况:
- token错误,这时需要用户重新登录,获取正确的token
- token过期,这时客户端需要再发起一次认证请求,获取新的token
然而,此种验证方式存在一个安全性问题:当登录接口被劫持时,黑客就获取到了用户密码和token,后续则可以对该用户做任何事情了。用户只有修改密码才能夺回控制权。
如何优化呢?第一种解决方案是采用HTTPS。HTTPS在HTTP的基础上添加了SSL安全协议,自动对数据进行了压缩加密,在一定程序可以防止监听、防止劫持、防止重发,安全性可以提高很多。不过,SSL也不是绝对安全的,也存在被劫持的可能。另外,服务器对HTTPS的配置相对有点复杂,还需要到CA申请证书,而且一般还是收费的。而且,HTTPS效率也比较低。一般,只有安全要求比较高的系统才会采用HTTPS,比如银行。而大部分对安全要求没那么高的App还是采用HTTP的方式。
我们目前的做法是给每个接口都添加签名。给客户端分配一个密钥,每次请求接口时,将密钥和所有参数组合成源串,根据签名算法生成签名值,发送请求时将签名一起发送给服务器验证。类似的实现可参考OAuth1.0的签名算法。这样,黑客不知道密钥,不知道签名算法,就算拦截到登录接口,后续请求也无法成功操作。不过,因为签名算法比较麻烦,而且容易出错,只适合对内的接口。如果你们的接口属于开放的API,则不太适合这种签名认证的方式了,建议还是使用OAuth2.0的认证机制。
我们也给每个端分配一个appKey,比如Android、iOS、微信三端,每个端分别分配一个appKey和一个密钥。没有传appKey的请求将报错,传错了appKey的请求也将报错。这样,安全性方面又加多了一层防御,同时也方便对不同端做一些不同的处理策略。
另外,现在越来越多App取消了密码登录,而采用手机号+短信验证码的登录方式,我在当前的项目中也采用了这种登录方式。这种登录方式有几种好处:
- 不需要注册,不需要修改密码,也不需要因为忘记密码而重置密码的操作了;
- 用户不再需要记住密码了,也不怕密码泄露的问题了;
- 相对于密码登录其安全性明显提高了。