我正在处理Django项目,并试图创建一个REST来验证电子邮件,而不使用任何数据库。我现在的服务器连接是HTTP,而不是HTTPS。
因此,使用API端点的人发电子邮件:
REQUEST:
curl --location --request POST 'http://127.0.0.1:8000/api/openlogin' \
--header 'Content-Type: application/json' \
--data-raw '{
"email":"test13@test.com",
}'
现在我正在生成一个随机的6位数,例如。435667
,一封电子邮件将发送给test13@test.com
:
send_mail('PIN TO VERIFY','ENTER THE PIN 435667',None,[test13@test.com])
435667
的HMAC值作为对API调用的响应发送:
raw = '435667'.encode("utf-8")
key = 'SOME_SECRET_KEY'.encode('utf-8')
hashed = hmac.new(key, raw, hashlib.sha1)
pin_hmac_hash = base64.encodebytes(hashed.digest()).decode('utf-8')
eg: pin_hmac_hash = "SOME_HMAC_HASH_OF_PIN"
因此,/api/openlogin
的响应将是:
{
'email': 'test13@test.com'
'pin': "SOME_HMAC_HASH_OF_PIN"
}
现在,用户将返回响应中的PIN和HMAC哈希:
curl --location --request POST 'http://127.0.0.1:8000/api/verifypin' \
--header 'Content-Type: application/json' \
--data-raw '{
'pin': "SOME_HMAC_HASH_OF_PIN",
'email': 'test13@test.com',
'emailed_pin':'435667'
}'
有人能猜到SOME_HMAC_HASH_OF_PIN
的密码吗?
当然,我将进一步尝试使用JWT令牌来修改API。所以电子邮件不能被篡改。
这是PIN的一个例子,但它可以是任何敏感信息字符串。我能依靠HMAC吗?
发布于 2020-02-04 02:34:05
听起来,您想要实现的是一个签名的URL,类似于Amazon。只要你的秘密是牢固和安全的,这听起来是一个合理的方式,以无状态的方式验证电子邮件地址。
目前,您只是在签名/使用PIN,这是您的代码中的一个问题。如果我从您的服务中得到一个有效的PIN/PIN_HASH组合,我仍然可以用一个新的电子邮件地址B提交这个有效的组合,它将通过您的验证测试。
我建议一个稍微不同的解决方案。使用时间戳代替PIN,并将其用作expirey日期。
created_at = int(round(time.time() * 1000))
payload = email + "-" + created_at
hashed = hmac.new(key, payload, hashlib.sha1)
然后将创建的时间发送回服务器,而不是发夹。这允许您在验证hmac签名是正确的之后,也可以检查这个请求有多老,如果它超过x分钟,则拒绝它。
这仍然使您很容易在时间范围内重播攻击,如果您检查用户还不存在,如果用户还不存在,则拒绝api调用,这样就可以了。
PS:如果没有https,您仍然面临着有人在信息到达您的服务器之前拦截和窃取这些信息的风险。我强烈建议使用https (LetsEncrypt证书是免费的,容易获得)
https://security.stackexchange.com/questions/225326
复制