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 · 6343 次点击
    这是一个创建于 3960 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这两天闲暇时在写一个小应用,遇到了用户注册后,发送激活邮件给用户用以激活帐号的设计问题。
    我目前的想法是这样的:在激活链接中传递三个参数,用户的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童鞋所说,达到目的就行,没必要纠结太多:)
    jyhmijack
        27
    jyhmijack  
       2014-02-20 12:15:26 +08:00
    自从全部使用uuid之后,更加幸福了
    jyhmijack
        28
    jyhmijack  
       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   ·   实用小工具   ·   2937 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 14:02 · PVG 22:02 · LAX 06:02 · JFK 09:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.