关于帐号激活邮件的设计 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
jayn1985
V2EX    Python

关于帐号激活邮件的设计

  •  
  •   jayn1985 2014-02-18 14:11:38 +08:00 6871 次点击
    这是一个创建于 4316 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这两天闲暇时在写一个小应用,遇到了用户注册后,发送激活邮件给用户用以激活帐号的设计问题。
    我目前的想法是这样的:在激活链接中传递三个参数,用户的email,发送此邮件时的时间戳ts,以及一个MD5加密后的字符串token(通过md5(secret, email, ts)得出),这样的话,用户在点击这个link后,服务器端获取相关的参数,首先校验token的有效性,通过md5(secret, 传过来的email地址,传过来的ts)与传过来的token比较,这样可以避免用户伪造ts和email;接着判断当前时间和ts的时间差是否满足一个合理的间隔(例如48h),如果一切都OK,那么就将用户设置为激活状态
    这种方法目前来看基本可以满足我的需求(至于是否健壮还望各位大大指教),但是这样的话激活link就会比较长,因为需要传送3个参数进去,我参考了下很多网站发送的激活邮件,有类似我这种格式的链接,也有的非常的简短,比如V2EX网站,其激活链接格式为: http://www.v2ex.com/activate/XXXXXXXX,所以我很好奇这种方式一般都是怎么校验的呢,难道需要在用户表中新增一个字段用来保存这个字符串,然后验证的时候只要比较下即可?那这种方式代价是不是高了些?所以恳请各位大大都来介绍下你们都是如何设计这个功能的?多谢~
    31 条回复    1970-01-01 08:00:00 +08:00
    loading
        1
    loading  
       2014-02-18 14:17:34 +08:00 via iPhone
    邮件里连接直接点,谁管长不长。

    btw:你md5每次都算啊…不也存起来吗?
    wingoo
        2
    wingoo  
       2014-02-18 14:18:20 +08:00
    新增一个验证表, 主键为guid, 其他字段可以为user_id, 过期时间等
    jayn1985
        3
    jayn1985  
    OP
       2014-02-18 14:41:28 +08:00
    @loading 你说每次都需要计算MD5,原因是如果用户更改了link中的email或者ts,那你在server端仍然需要计算一下当前计算出的MD5值和传来的token值是否匹配吧,否则你怎么验证用户没有更改你的激活链接呢?
    justfindu
        4
    justfindu  
       2014-02-18 14:53:46 +08:00
    @jayn1985 验证email和token search一下sql ,带上token过期时间的条件 没有就说明不是正确用户
    lichao
        5
    lichao  
       2014-02-18 14:56:01 +08:00
    我觉得只需一个 token 就行,其它的都多余
    jayn1985
        6
    jayn1985  
    OP
       2014-02-18 15:05:45 +08:00
    @lichao 那server端是如何做验证的呢?求详细解答,多谢:)
    lichao
        7
    lichao  
       2014-02-18 15:07:31 +08:00
    @jayn1985 你 server 端,有个表,根据这个唯一的 token,即可确定是哪个用户了,然后。。。。。。
    jayn1985
        8
    jayn1985  
    OP
       2014-02-18 15:12:58 +08:00
    @lichao 你的意思是加张表或者是在User表里面加个字段存这个token么?那用户激活成功了的话,这个信息之后还有用么?如果没有用的话,这样设计是不是代价高了些?
    lichao
        9
    lichao  
       2014-02-18 15:17:43 +08:00
    @jayn1985 自然是放另外一个表。嗯,弊端就是这个信息之后就没用了
    dorentus
        10
    dorentus  
       2014-02-18 15:19:57 +08:00
    单独加张表放 token,用完删。怕慢就用 redis 之类的存。

    这个代价不高的;等你在这个地方遇到瓶颈的时候,你的系统的其它部分估计都已经遇到过 n 次瓶颈、重写多遍了……
    jayn1985
        11
    jayn1985  
    OP
       2014-02-18 15:27:36 +08:00
    @lichao 我在网上搜了相关文章,很多也都是类似你这样的设计,我很想知道这种设计的原因,是因为很难构造出一个健壮的方式来避免安全问题么?抱歉想得太多,呵呵~
    vob636
        12
    vob636  
       2014-02-18 15:37:24 +08:00
    @dorentus +1用完肯定删……@jayn1985 楼上的已经很健壮了……各种token了……是在不行,你加上https……
    jayn1985
        13
    jayn1985  
    OP
       2014-02-18 15:42:11 +08:00
    @dorentus 感谢回复,加表后对其操作确实代价不大,但是我总觉得因为这么一个不算大的feature而要新增一张表,这个有点“杀鸡用牛刀”的感觉:)也许在不新增新的实体的前提下,来做这个email校验确实没有完全周到的想法(我自己设想的方法可能确实有漏洞,但是不是做安全出身的所以目前还没看出来。。)
    lichao
        14
    lichao  
       2014-02-18 15:45:55 +08:00
    @jayn1985 @jayn1985 我只是觉得这种方式最简单有效,安全性方面也没有缺陷
    family
        15
    family  
       2014-02-18 15:46:16 +08:00 via iPhone
    直接加字段或表 有时间纠结的功夫多达游戏
    jayn1985
        16
    jayn1985  
    OP
       2014-02-18 15:49:59 +08:00
    @family 哈哈:)
    jayn1985
        17
    jayn1985  
    OP
       2014-02-18 15:51:05 +08:00
    @lichao 呵呵,是的,还是很感谢回复啊:)
    ksc010
        18
    ksc010  
       2014-02-18 16:10:11 +08:00
    突然想到一个问题,把点击放到email中
    QQ这样的邮件服务商会不会为了安全原因访问这个url?
    目前看来来应该没有这种情况
    ksc010
        19
    ksc010  
       2014-02-18 16:13:22 +08:00
    也可以放到session
    但是有个问题会话结束后 链接就失效了
    换个浏览器也不行
    cevincheung
        20
    cevincheung  
       2014-02-19 01:05:02 +08:00
    你的方案完全可以啊。连接直接点就是的。不用管长度。参考一下其他厂商的邮件范本就 可以了嘛。

    http://domain.com/verify?email=x&ts=x&sign=x

    服务端保存一个公共密钥。这样sign的值也根本不需要保存。ts可以用来判断连接是否过期,而且这个过期时间可以自己随意控制。
    jayn1985
        21
    jayn1985  
    OP
       2014-02-19 08:50:44 +08:00
    @wingoo
    @vob636
    @ksc010
    @cevincheung
    目前先使用原方案做着了,感谢各位的回复~
    yayu
        22
    yayu  
       2014-02-19 13:38:08 +08:00
    @jayn1985 原方案url中暴露用户email,不好。不想加表可以吧email+salt+time用非对称加解密。
    lygmqkl
        23
    lygmqkl  
       2014-02-19 19:54:25 +08:00
    其实有没有考虑过使用user表内的一些不变元素来实现这个功能? 比如说 MD5(email.password) 在用户不修改密码的前提下,只需要增加用户的id 到 verify url 就可以了类似 lee.com/v/1/hashstring 因为在你生成验证之前用户已经保存了,可以额外增加一个字段比如 user_active = 0/1/2 0-new 1-actived 2-blocked.
    geew
        24
    geew  
       2014-02-20 09:20:42 +08:00
    楼主的方法和我现在用的方法是一样的, 其实这样就够了, 达到目的就行. 然后其他的方法虽然可以让URL看起来清爽点, 但其实差不多. 比如那个建立一张表的方法, 感觉没有必要, 毕竟验证结束了就没啥用了, 感觉浪费了. PS: 这个问题真心不需要纠结....
    geew
        25
    geew  
       2014-02-20 09:24:24 +08:00
    @yayu
    @jayn1985
    其实校验url里面可以不用email, 用用户id就行了. 然后把id和ts做个签名, 生成token. url带上这个三个参数就行.
    至于暴露问题, 用户id可以设计为一个随机串, 不用数字的方式则更好了. 另, 用户自身的id给他暴露又有什么关系呢
    jayn1985
        26
    jayn1985  
    OP
       2014-02-20 09:40:35 +08:00
    @yayu
    @lygmqkl
    @geew
    感谢回复,如geew童鞋所说,达到目的就行,没必要纠结太多:)
    KKKKale
        27
    KKKKale  
       2014-02-20 12:15:26 +08:00
    自从全部使用uuid之后,更加幸福了
    KKKKale
        28
    KKKKale  
       2014-02-20 12:15:56 +08:00
    用redis缓存住token对应的uid,过期时间就好了
    phpcxy
        29
    phpcxy  
       2014-02-20 14:02:04 +08:00
    我现在也是楼主这样的方案,邮件里面给一个按钮他点击。
    drivel
        30
    drivel  
       2014-02-20 16:16:07 +08:00
    @ksc010 Apple 家的 iTunes Store 的做法就是,点击进去之后,需要重新输入账号和密码验证才能激活

    那么,完全可以在激活页面加上一个 input form,验证下密码就好
    ksc010
        31
    ksc010  
       2014-02-20 22:03:28 +08:00
    @drivel 重点是验证该用户是邮箱的所有者,也就是说有个“token”是只有邮箱所有者与系统知道才行
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2697 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 13:40 PVG 21:40 LAX 05:40 JFK 08:40
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86