注册或邀请电子邮件验证w/o数据库

时间:2022-09-15 18:24:00

I'd like to keep my database clean of stale almost-accounts, and I was thinking about making new signups and invitations put their data into the welcome email as an encrypted or hashed url. Once the link in the url is visited, the information is then added into the database as an account. Is there something that currently does this? Any references, thoughts, or warnings about doing user registration this way? Thanks!

我想让我的数据库保持干净的几乎陈旧的帐户,我正在考虑制作新的签名和邀请把他们的数据作为一个加密或散列的url放到欢迎电子邮件中。访问url中的链接后,信息作为帐户添加到数据库中。有什么东西是现在做的吗?使用这种方式进行用户注册的任何引用、想法或警告?谢谢!

Edit: I've made a working example, and the url is 127 characters.

编辑:我做了一个工作示例,url是127个字符。

http://localhost/confirm?_=hBRCGVqie5PetQhjiagq9F6kmi7luVxpcpEYMWaxrtSHIPA3rF0Hufy6EgiH%0A%2BL3t9dcgV9es9Zywkl4F1lcMyA%3D%3D%0A

Obviously, more data = larger url

显然,更多的数据=更大的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

5 个解决方案

#1


6  

Thoughts:

想法:

  • Use true asymmetric cypher for the "cookie" to prevent bots creating accounts. Encrypt the "cookie" using public key, verify it by decoding with private key.
    Rationale: If only a base64 or other algorithm was used for encoding the cookie, it would be easy to reverse-engineer the scheme and create accounts automatically. This is undesirable because of spambots. Also, if the account is password protected, the password would have to appear in the cookie. Anyone with access to the registration link would be able not only to activate the account, but also to figure out the password.

    对“cookie”使用真正的非对称密码,以防止机器人创建账户。使用公钥加密“cookie”,通过私钥解码进行验证。原理:如果只使用base64或其他算法对cookie进行编码,那么就很容易对scheme进行反向工程,并自动创建帐户。这是不受欢迎的,因为垃圾邮件机器人。此外,如果帐户是密码保护的,密码必须出现在cookie中。任何人只要能进入注册链接,就不仅能激活账号,还能计算出密码。

  • Require re-entry of the password after activation through the link.
    Rationale: Depending on the purpose of the site you may want to improve the protection against information spoofing. Re-entering the password after activation protects against stolen/spoofed activation links.

    在激活后需要重新输入密码。基本原理:根据站点的目的,您可能希望改进对信息欺骗的保护。激活后重新输入密码可以防止被盗/欺骗激活链接。

  • When verifying the activation link, make sure the account created by it is not created already.

    在验证激活链接时,请确保它创建的帐户尚未创建。

  • How do you protect against two users simultaneously creating an account with the same name?
    Possible answer: Use email as the login identifier and don't require unique account name.

    如何防止两个用户同时创建同名帐户?可能的答案:使用电子邮件作为登录标识符,不需要唯一的帐户名。

  • Verify the email first, than continue account creation.
    Rationale: This will minimize the information you need to send in the cookie.

    先验证邮件,然后继续创建帐户。基本原理:这将最小化您需要在cookie中发送的信息。

#2


4  

  • There are some e-mail clients which break URLs after 80 letters. I doubt that you can fit all the information in there.

    有一些电子邮件客户端在80个字母后破坏url。我怀疑你是否能把所有的资料都装进去。

  • Some browsers have limitations for the URL, Internet Explorer 8 has a limit of 2083 characters, for example.

    有些浏览器对URL有限制,例如Internet Explorer 8有2083个字符的限制。

Why don't you clean your database regularly (cron script) and remove all accounts that haven't been activated for 24 houres?

你为什么不定期清理你的数据库(cron脚本)并删除所有未被激活的帐号?

#3


3  

I have done pretty much the same before. I only have 2 suggestions for you,

我以前也做过类似的事情。我只有两个建议,

  1. Add a key version so you can rotate the key without breaking outstanding confirmation.
  2. 添加一个密钥版本,这样您就可以旋转密钥而不会破坏突出的确认。
  3. You need a timestamp or expiration so you can set a time limit on confirmation if you want to. We allow one week.
  4. 您需要一个时间戳或过期,以便您可以在确认时设置时间限制。我们允许一个星期。

As to the shortest URL, you can do better by making following changes,

对于最短的URL,您可以通过以下更改来做得更好,

  1. Use a stream cipher mode like CFB so you don't have to pad to the block size.
  2. 使用流密码模式,如CFB,这样您就不必填充到块大小。
  3. Compress the cleartext will help when the data is big. I have a flag and only use compression when it shrinks data.
  4. 当数据很大时,压缩cleartext会有帮助。我有一个标志,只有当它收缩数据时才使用压缩。
  5. Use Base64.urlsafe_encode64() so you don't have to URL encode it.
  6. 使用Base64.urlsafe_encode64(),这样就不用URL编码了。

#4


3  

There's a few problems with your solution.

你的解决方案有几个问题。

Firstly, you're not setting the IV of the cipher. In my view this has exposed a serious bug in the Ruby OpenSSL wrapper - it shouldn't let you perform an encryption or decryption until both key and iv have been set, but instead it's going ahead and using an IV of all-zeroes. Using the same IV every time basically removes much of the benefit of using a feedback mode in the first place.

首先,你没有设置密码的IV。在我看来,这在Ruby OpenSSL包装器中暴露了一个严重的bug——它不应该让您执行加密或解密,直到密钥和iv都被设置好,而是使用全零的iv。每次都使用相同的IV,基本上从一开始就消除了使用反馈模式的好处。

Secondly, and more seriously, you have no authenticity checking. One of the properties of CBC mode is that an attacker who has access to one message can modify it to create a second message where a block in the second message has entirely attacker-controlled contents, at the cost of the prior block being completely garbled. (Oh, and note that CFB mode is just as much a problem in this regard).

其次,更严重的是,你没有真实性检查。CBC模式的一个特性是,访问一个消息的攻击者可以修改它,创建第二个消息,其中第二个消息中的块拥有完全受攻击控制的内容,代价是前面的块被完全打乱。(哦,请注意,CFB模式在这方面也同样是个问题)。

In this case, that means that I could request an account with Last Name of AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA and my own email address to recieve a valid URL. I can then, without knowing the key, modify the email address to victim@victim.com (and garble the Last Name in the process, which doesn't matter), and have a valid URL which I can submit to your server and create accounts for email addresses that I don't control.

在本例中,这意味着我可以请求一个姓氏为aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa的帐户以及我自己的电子邮件地址来接收一个有效的URL。然后,在不知道密钥的情况下,我可以将电子邮件地址修改为受害人@ victims . .com(并在处理过程中篡改姓,这并不重要),并拥有一个有效的URL,我可以提交给您的服务器,为我无法控制的电子邮件地址创建帐户。

To solve this, you need to compute a HMAC over the data, keyed with a secret that only the server knows, and send that as part of the URL. Note that the only reason you need encryption at all here is to secure the user's password - other than that it could just be plaintext plus a HMAC. I suggest you simply send as the url something like:

要解决这个问题,您需要在数据上计算一个HMAC,键入一个只有服务器知道的秘密,并将其作为URL的一部分发送出去。注意,您需要加密的唯一原因是为了保护用户的密码——除了可以是纯文本和HMAC。我建议您简单地以url的形式发送:

?ln=Last%20Name&fn=First%20Name&email=foo@bar.com&hmac=7fpsQba2GMepELxilVUEfwl3%2BN1MdCsg%2FZ59dDd63QE%3D

...and have the verification page prompt for a password (there doesn't seem to be a reason to bounce the password back and forth).

…并有验证页面提示输入密码(似乎没有理由来回反弹密码)。

#5


1  

I will take a crack at describing a design that may work.

我将在描述一个可能有用的设计时采取一些措施。

Prerequisities:

先决条件:

  • Cryptography library with support for RSA and some secure hash function H (eg. SHA-1)
  • 支持RSA和一些安全哈希函数H的密码学库。sha - 1)
  • One pair of private and public keys
  • 一对私钥和公钥

Design:

设计:

  • Unique user identifier is e-mail address
  • 唯一的用户标识符是电子邮件地址
  • An account has associated password and possible other data
  • 帐户具有关联的密码和可能的其他数据
  • The activation cookie is kept as small as possible
  • 激活cookie越小越好

Process:

过程:

  • User is asked for e-mail address and password. Upon submission of the form a cookie is computed as cookie = ENCRYPT(CONCAT(email, '.', H(password)), public key)
  • 用户需要电子邮件地址和密码。在提交表单时,cookie = ENCRYPT(CONCAT, email, ')。”,H(密码)),公共密钥)
  • E-mail is sent containing a link to the activation page with the cookie, eg. http://example.org/activation?cookie=[cookie]
  • 电子邮件被发送,其中包含到使用cookie的激活页面的链接。http://example.org/activation?cookie=(饼干)
  • The activation page at http://example.org/activation decrypts the cookie passed as parameter: data = SPLIT(DECRYPT(cookie, private key), '.')
  • 在http://example.org/activation上的激活页解密作为参数传递的cookie: data = SPLIT(DECRYPT(cookie, private key), ')。
  • In the same activation page the user is asked for password (which must be hashed to the the same value as in cookie) and any other information necessary for the account creation
  • 在相同的激活页面中,用户被要求输入密码(必须将密码散列到与cookie中相同的值)以及创建帐户所需的任何其他信息
  • Upon submission of the activation page a new account is created
  • 在提交激活页面时,将创建一个新帐户

Please point out anything that I have missed or any improvements. I'd be glad to update the answer accordingly.

请指出我遗漏了什么或有什么改进。我很乐意相应地更新答案。

#1


6  

Thoughts:

想法:

  • Use true asymmetric cypher for the "cookie" to prevent bots creating accounts. Encrypt the "cookie" using public key, verify it by decoding with private key.
    Rationale: If only a base64 or other algorithm was used for encoding the cookie, it would be easy to reverse-engineer the scheme and create accounts automatically. This is undesirable because of spambots. Also, if the account is password protected, the password would have to appear in the cookie. Anyone with access to the registration link would be able not only to activate the account, but also to figure out the password.

    对“cookie”使用真正的非对称密码,以防止机器人创建账户。使用公钥加密“cookie”,通过私钥解码进行验证。原理:如果只使用base64或其他算法对cookie进行编码,那么就很容易对scheme进行反向工程,并自动创建帐户。这是不受欢迎的,因为垃圾邮件机器人。此外,如果帐户是密码保护的,密码必须出现在cookie中。任何人只要能进入注册链接,就不仅能激活账号,还能计算出密码。

  • Require re-entry of the password after activation through the link.
    Rationale: Depending on the purpose of the site you may want to improve the protection against information spoofing. Re-entering the password after activation protects against stolen/spoofed activation links.

    在激活后需要重新输入密码。基本原理:根据站点的目的,您可能希望改进对信息欺骗的保护。激活后重新输入密码可以防止被盗/欺骗激活链接。

  • When verifying the activation link, make sure the account created by it is not created already.

    在验证激活链接时,请确保它创建的帐户尚未创建。

  • How do you protect against two users simultaneously creating an account with the same name?
    Possible answer: Use email as the login identifier and don't require unique account name.

    如何防止两个用户同时创建同名帐户?可能的答案:使用电子邮件作为登录标识符,不需要唯一的帐户名。

  • Verify the email first, than continue account creation.
    Rationale: This will minimize the information you need to send in the cookie.

    先验证邮件,然后继续创建帐户。基本原理:这将最小化您需要在cookie中发送的信息。

#2


4  

  • There are some e-mail clients which break URLs after 80 letters. I doubt that you can fit all the information in there.

    有一些电子邮件客户端在80个字母后破坏url。我怀疑你是否能把所有的资料都装进去。

  • Some browsers have limitations for the URL, Internet Explorer 8 has a limit of 2083 characters, for example.

    有些浏览器对URL有限制,例如Internet Explorer 8有2083个字符的限制。

Why don't you clean your database regularly (cron script) and remove all accounts that haven't been activated for 24 houres?

你为什么不定期清理你的数据库(cron脚本)并删除所有未被激活的帐号?

#3


3  

I have done pretty much the same before. I only have 2 suggestions for you,

我以前也做过类似的事情。我只有两个建议,

  1. Add a key version so you can rotate the key without breaking outstanding confirmation.
  2. 添加一个密钥版本,这样您就可以旋转密钥而不会破坏突出的确认。
  3. You need a timestamp or expiration so you can set a time limit on confirmation if you want to. We allow one week.
  4. 您需要一个时间戳或过期,以便您可以在确认时设置时间限制。我们允许一个星期。

As to the shortest URL, you can do better by making following changes,

对于最短的URL,您可以通过以下更改来做得更好,

  1. Use a stream cipher mode like CFB so you don't have to pad to the block size.
  2. 使用流密码模式,如CFB,这样您就不必填充到块大小。
  3. Compress the cleartext will help when the data is big. I have a flag and only use compression when it shrinks data.
  4. 当数据很大时,压缩cleartext会有帮助。我有一个标志,只有当它收缩数据时才使用压缩。
  5. Use Base64.urlsafe_encode64() so you don't have to URL encode it.
  6. 使用Base64.urlsafe_encode64(),这样就不用URL编码了。

#4


3  

There's a few problems with your solution.

你的解决方案有几个问题。

Firstly, you're not setting the IV of the cipher. In my view this has exposed a serious bug in the Ruby OpenSSL wrapper - it shouldn't let you perform an encryption or decryption until both key and iv have been set, but instead it's going ahead and using an IV of all-zeroes. Using the same IV every time basically removes much of the benefit of using a feedback mode in the first place.

首先,你没有设置密码的IV。在我看来,这在Ruby OpenSSL包装器中暴露了一个严重的bug——它不应该让您执行加密或解密,直到密钥和iv都被设置好,而是使用全零的iv。每次都使用相同的IV,基本上从一开始就消除了使用反馈模式的好处。

Secondly, and more seriously, you have no authenticity checking. One of the properties of CBC mode is that an attacker who has access to one message can modify it to create a second message where a block in the second message has entirely attacker-controlled contents, at the cost of the prior block being completely garbled. (Oh, and note that CFB mode is just as much a problem in this regard).

其次,更严重的是,你没有真实性检查。CBC模式的一个特性是,访问一个消息的攻击者可以修改它,创建第二个消息,其中第二个消息中的块拥有完全受攻击控制的内容,代价是前面的块被完全打乱。(哦,请注意,CFB模式在这方面也同样是个问题)。

In this case, that means that I could request an account with Last Name of AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA and my own email address to recieve a valid URL. I can then, without knowing the key, modify the email address to victim@victim.com (and garble the Last Name in the process, which doesn't matter), and have a valid URL which I can submit to your server and create accounts for email addresses that I don't control.

在本例中,这意味着我可以请求一个姓氏为aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa的帐户以及我自己的电子邮件地址来接收一个有效的URL。然后,在不知道密钥的情况下,我可以将电子邮件地址修改为受害人@ victims . .com(并在处理过程中篡改姓,这并不重要),并拥有一个有效的URL,我可以提交给您的服务器,为我无法控制的电子邮件地址创建帐户。

To solve this, you need to compute a HMAC over the data, keyed with a secret that only the server knows, and send that as part of the URL. Note that the only reason you need encryption at all here is to secure the user's password - other than that it could just be plaintext plus a HMAC. I suggest you simply send as the url something like:

要解决这个问题,您需要在数据上计算一个HMAC,键入一个只有服务器知道的秘密,并将其作为URL的一部分发送出去。注意,您需要加密的唯一原因是为了保护用户的密码——除了可以是纯文本和HMAC。我建议您简单地以url的形式发送:

?ln=Last%20Name&fn=First%20Name&email=foo@bar.com&hmac=7fpsQba2GMepELxilVUEfwl3%2BN1MdCsg%2FZ59dDd63QE%3D

...and have the verification page prompt for a password (there doesn't seem to be a reason to bounce the password back and forth).

…并有验证页面提示输入密码(似乎没有理由来回反弹密码)。

#5


1  

I will take a crack at describing a design that may work.

我将在描述一个可能有用的设计时采取一些措施。

Prerequisities:

先决条件:

  • Cryptography library with support for RSA and some secure hash function H (eg. SHA-1)
  • 支持RSA和一些安全哈希函数H的密码学库。sha - 1)
  • One pair of private and public keys
  • 一对私钥和公钥

Design:

设计:

  • Unique user identifier is e-mail address
  • 唯一的用户标识符是电子邮件地址
  • An account has associated password and possible other data
  • 帐户具有关联的密码和可能的其他数据
  • The activation cookie is kept as small as possible
  • 激活cookie越小越好

Process:

过程:

  • User is asked for e-mail address and password. Upon submission of the form a cookie is computed as cookie = ENCRYPT(CONCAT(email, '.', H(password)), public key)
  • 用户需要电子邮件地址和密码。在提交表单时,cookie = ENCRYPT(CONCAT, email, ')。”,H(密码)),公共密钥)
  • E-mail is sent containing a link to the activation page with the cookie, eg. http://example.org/activation?cookie=[cookie]
  • 电子邮件被发送,其中包含到使用cookie的激活页面的链接。http://example.org/activation?cookie=(饼干)
  • The activation page at http://example.org/activation decrypts the cookie passed as parameter: data = SPLIT(DECRYPT(cookie, private key), '.')
  • 在http://example.org/activation上的激活页解密作为参数传递的cookie: data = SPLIT(DECRYPT(cookie, private key), ')。
  • In the same activation page the user is asked for password (which must be hashed to the the same value as in cookie) and any other information necessary for the account creation
  • 在相同的激活页面中,用户被要求输入密码(必须将密码散列到与cookie中相同的值)以及创建帐户所需的任何其他信息
  • Upon submission of the activation page a new account is created
  • 在提交激活页面时,将创建一个新帐户

Please point out anything that I have missed or any improvements. I'd be glad to update the answer accordingly.

请指出我遗漏了什么或有什么改进。我很乐意相应地更新答案。