Ruby on rails 注册或邀请电子邮件验证,不含数据库
我想保持我的数据库中几乎没有过时的帐户,我正在考虑进行新的注册和邀请,将他们的数据作为加密或散列的url放入欢迎电子邮件中。访问url中的链接后,该信息将作为帐户添加到数据库中。 目前有什么东西可以做到这一点吗?关于以这种方式进行用户注册有任何参考、想法或警告吗? 谢谢 编辑: 我已经做了一个工作示例,url是127个字符Ruby on rails 注册或邀请电子邮件验证,不含数据库,ruby-on-rails,ruby,database,encryption,encoding,Ruby On Rails,Ruby,Database,Encryption,Encoding,我想保持我的数据库中几乎没有过时的帐户,我正在考虑进行新的注册和邀请,将他们的数据作为加密或散列的url放入欢迎电子邮件中。访问url中的链接后,该信息将作为帐户添加到数据库中。 目前有什么东西可以做到这一点吗?关于以这种方式进行用户注册有任何参考、想法或警告吗? 谢谢 编辑: 我已经做了一个工作示例,url是127个字符 http://localhost/confirm?_=hBRCGVqie5PetQhjiagq9F6kmi7luVxpcpEYMWaxrtSHIPA3rF0Hufy6EgiH
http://localhost/confirm?_=hBRCGVqie5PetQhjiagq9F6kmi7luVxpcpEYMWaxrtSHIPA3rF0Hufy6EgiH%0A%2BL3t9dcgV9es9Zywkl4F1lcMyA%3D%3D%0A
显然,数据越多,url越大
def create
# Write k keys in params[:user] as v keys in to_encrypt, doing this saves LOTS of unnecessary chars
@to_encrypt = Hash.new
{:firstname => :fn,:lastname => :ln,:email => :el,:username => :un,:password => :pd}.each do |k,v|
@to_encrypt[v] = params[:user][k]
end
encrypted_params = CGI::escape(Base64.encode64(encrypt(compress(Marshal.dump(@to_encrypt)), "secret")))
end
private
def aes(m,t,k)
(aes = OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key = Digest::SHA256.digest(k)
aes.update(t) << aes.final
end
def encrypt(text, key)
aes(:encrypt, text, key)
end
def decrypt(text, key)
aes(:decrypt, text, key)
end
# All attempts to compress returned a longer url (Bypassed by return)
def compress(string)
return string
z = Zlib::Deflate.new(Zlib::BEST_COMPRESSION)
o = z.deflate(string,Zlib::FINISH)
z.close
o
end
def decompress(string)
return string
z = Zlib::Inflate.new
o = z.inflate(string)
z.finish
z.close
o
end
def创建
#将params[:user]中的k密钥作为v密钥写入_encrypt,这样做可以节省大量不必要的字符
@to_encrypt=Hash.new
{:firstname=>:fn,:lastname=>:ln,:email=>:el,:username=>:un,:password=>:pd}。每个do | k,v|
@加密[v]=params[:user][k]
结束
encrypted_params=CGI::escape(Base64.encode64(encrypt(compress(Marshal.dump(@to_encrypt)),“secret”))
结束
私有的
def aes(m、t、k)
(aes=OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key=Digest::SHA256.Digest(k)
aes.更新(t)想法:
- 对“cookie”使用真正的非对称密码,以防止机器人创建帐户。使用公钥加密“cookie”,使用私钥解码验证它。
理由:如果仅使用base64或其他算法对cookie进行编码,则很容易对方案进行反向工程并自动创建帐户。这是不可取的,因为spambots。此外,如果帐户受密码保护,则密码必须出现在cookie中。任何有权访问注册链接的人都将不仅能够激活该帐户,而且能够计算出密码
- 通过链接激活后需要重新输入密码。
理由:根据网站的用途,您可能希望提高对信息欺骗的保护。激活后重新输入密码可防止被盗/伪造的激活链接
- 验证激活链接时,请确保它创建的帐户尚未创建。
- 如何防止两个用户同时创建同名帐户?
可能的答案:使用电子邮件作为登录标识符,不需要唯一的帐户名
- 首先验证电子邮件,然后继续创建帐户。
理由:这将最大限度地减少您需要在cookie中发送的信息
- 有些电子邮件客户端会在80个字母后中断URL。我怀疑你能把所有的信息都放进去
- 一些浏览器对URL有限制,例如限制为2083个字符
为什么不定期清理数据库(cron脚本)并删除24小时内未激活的所有帐户?我将尝试描述一种可能有效的设计
先决条件:
- 支持RSA和一些安全哈希函数H(如SHA-1)的密码库
- 一对私钥和公钥
设计:
- 唯一用户标识符是电子邮件地址
- 帐户具有关联的密码和可能的其他数据
- 激活cookie尽可能小
过程:
- 要求用户提供电子邮件地址和密码。提交表单时,cookie计算为
cookie=ENCRYPT(CONCAT(电子邮件),H(密码)),公钥)
- 发送的电子邮件包含指向带有cookie的激活页面的链接,例如。
http://example.org/activation?cookie=[cookie]
- 激活页面位于
http://example.org/activation
对作为参数传递的cookie进行解密:data=SPLIT(解密(cookie,私钥),'.'))
- 在同一激活页面中,要求用户输入密码(密码必须散列到与cookie中相同的值)以及创建帐户所需的任何其他信息
- 提交激活页面后,将创建一个新帐户
请指出我遗漏的任何内容或任何改进。我很乐意相应地更新答案。我以前也做过类似的事情。我只有两条建议给你
- 添加密钥版本,以便在不中断未完成确认的情况下旋转密钥
- 您需要一个时间戳或到期日,以便您可以在确认时设置一个时间限制。我们有一周的时间
至于最短的URL,您可以通过以下更改做得更好
- 使用流密码模式,如CFB,这样就不必填充到块大小李>
- 当数据较大时,压缩明文会有所帮助。我有一个标志,只在压缩数据时使用压缩
- 使用
Base64.urlsafe\u encode64()
你的解决方案有一些问题
首先,您没有设置密码的IV。在我看来,这暴露了Ruby OpenSSL包装中的一个严重缺陷—在设置了
密钥
和iv
之前,它不应该让您执行加密或解密,但是它正在继续,并且使用了全零的iv。每次使用同一个IV基本上从一开始就消除了使用反馈模式的许多好处
其次,更严重的是,你没有真实性检查。CBC模式的一个特性是,可以访问一条消息的攻击者可以修改该消息以创建第二条消息,其中第二条消息中的块具有完全由攻击者控制的内容,而代价是先前的块被完全篡改。(哦,注意循环流化床模式在这方面也是一个问题)
在这种情况下,这意味着我可以
?ln=Last%20Name&fn=First%20Name&email=foo@bar.com&hmac=7fpsQba2GMepELxilVUEfwl3%2BN1MdCsg%2FZ59dDd63QE%3D