Open zonyitoo opened 11 years ago
其实我觉得没有必要设置token的过期时间,token一开始的目的只是为了防止多终端登录而已,我们只需要保证这个token的唯一性就OK了,然后在登录的时候根据这个token来生成一对密钥,然后服务端要保存好每个客户端对应的token,server_public_key,server_secret_key,client_public_key。
服务端不必针对每个Client生成一对密钥的吧,而且client_public_key
在登录完成之后没有必要再保存
如果token
不过期,那样token
被盗之后就坏了。过期之后让客户端重新登录也不是难事
针对每个Client生成一对密钥的目的不是为了应对多终端登录的情况么?不然多终端登录同一个用户所生成的密钥对都是一样的,这样设置个clientID就没有用了,如果你真的想要token过期的话,把token的过期时间设置成一个很大的数把,比如两个星期甚至一个月什么的,太短比如一天还不如不过期
nounce
值每次都不同,而服务器能做的就是验证其与上一次不同,那样攻击将非常简单:
Authorization
头Authorization
头去请求如此即成功攻击。
每次将timestamp都发送过去,然后服务器收到这个timestamp之后,跟服务器的当前timestamp比对,如果差值在一定范围内,则认证通过
这个方法最具可操作性,这个差值可设为一个商定的值,如3分钟。需要长时间的请求可压缩。
其实,如果上传图片的菊花转了2分钟还没反应的话,那已经是超越人类可忍受的极限了。
你所说的只检查上一次所会出现的问题,我也想过,有种办法就是记录所有的nounce
的值,或者只记录一段请求之内的,可是对于我们这种bbs应用来说,我觉得就记录上一次就OK了,因为我们的应用估计还不用这么高的安全系数。
没有绝对的安全,我们只需要让破解变得稍微困难点就OK了 在没有https的情况下,可以认为无论怎样做都是可破解的。
那就用类似将军令吧,相对于发随机字符串,开销比较小也比较容易实现。发Timestamp的方法那就真的要持续监听了,就只有几分钟的时间可以伪装。
还可以再加一层,在Redis储存上一次请求的Timestamp,每一次请求的时间戳要求一定要比上一次的时间戳大,那样即使监听到也没用了,因为我都用了一次了,你用不了了。
行,那就直接存timestamp吧,其实用将军令那个方法也会有问题啊,因为你在一个time range里面的值都是一样的,那我们就直接要求为timestamp咯,如果这次发送的值小于等于上次的就认为认证不通过了。我先改下协议
我加了一句:用base64 encode一下传输的信息,因为rsa加密之后的信息好像不太适合放在Header直接传
好,我先改下auth.py
吧,不过似乎现在github push不了。。
已经改好了,你检查一下,你有testcase么?测一个
我把base64的decode和encode都重新放在__rsa128_encrypt_str
和__rsa128_decrypt_str
这两个方法里面了,测试的话我晚点再撸吧。
登录认证流程
由于后台目前只能接受
Plain Text
认证,所以需要在认证流程开始前把数据加密,在服务器端解密。加密算法使用RSA128
,认证过程中传输的数据都放在Authorization
头中,传输过程中把Authorization
头中信息使用base64.urlsafe_b64encode
编码,流程如下:前提:服务器生成
PublicKey: PrivateKey
对,存在配置文件中(固定)server_publickey
,并把自己的client_publickey
发给服务器,请求格式为:密钥使用
PKCS#1
格式传输。login_token
和server_publickey
,格式为状态码
200
,密钥使用PKCS#1
格式传输。服务器生成一个UUID作为login_token
,在Redis中储存键值对其中
[login_token]
为生成的login_token
,并设置过期时间为120分钟。即120分钟内必须完成这次登录流程,否则回到第1步。server_publickey
对发送数据进行加密,发送数据格式为:其中
login_token
为第2步时从服务器得到。client_publickey
加密回复数据,回复数据格式为:服务器在此步生成一个UUID作为
access_token
,在Redis中储存键值对其中
[access_token]
为生成的access_token
,过期时间为30天。登录成功后,此次登录所使用的login_token
即可销毁。回复的
body
部分success
为true
,状态码200
;否则为false
,状态码401
,errmsg
给出错误原因。补充流程
login_token
过期每次认证所使用的
login_token
都是不同的,服务器上会对它设置过期时间,若第3步中login_token
已过期,则服务器回复:状态码
401
,客户端重新发起流程即可。状态码为
400
,客户端需要重新发起流程。加密传输
在成功获得
access_token
后,每次的请求都要把access_token
使用server_publickey
加密后置于HTTP头Authorization
域中,格式为服务器获取到
access_token
后,到Redis中寻找Keyauth:access_token:[access_token]
,其中[access_token]
为获取到的access_token
,若该Key存在,则用户已登录;否则用户未登录或认证已过期,统一返回未认证,而nounce
为发起请求时的时间戳,精确到秒。服务器将收到的时间戳与上一次的nounce
值比较,若相等或小于上一次的nounce
,则认为认证已过期。若认证已过期,服务器会即时返回
状态码
401
。