2013-05-02 87 views
6

我国政府已经限制HTTPS速度来阻止访问伊朗外的安全Web服务。现在我的客户很难登录到他们的账户。我知道使用pbkdf2_sha256算法对当前帐户密码进行了加密和盐渍处理,并且有一些javascript/jQuery库来消化sha256哈希值。使用sha256哈希代替纯文本密码

我的问题:是否有任何无痛的方式(不需要重写/更改原始django.contrib.auth)使用由AJAX请求发送的sha256散列作为登录密码?

更新:我打算在伊朗境内托管我的网站(这是贵的5倍,当然受政府控制),但至少HTTPS协议不受限制。无论如何,通过HTTP通道以纯文本或消解方式发送密码是不安全的。作为一名Web开发人员(而不是网络专家),我认为他们可以随时收集/嗅探散列/会话ID/Cookie,解决问题需要复杂的知识和努力,毕竟我的网站不需要安全级别。我们生活在不同的星球上。

+1

欢迎来到Stack Overflow。请[尝试使用更礼貌的语言](http://meta.stackexchange.com/questions/22232/are-expletives-allowed-on-se-sites/22233#22233)。 – nnnnnn 2013-05-02 13:30:51

+3

谢谢。不好意思。我在过去的33个小时里没有睡觉,并且因为一个并非由我的错误而导致的问题而让我头部受伤。 – GhaghaSibil 2013-05-02 13:38:03

回答

3

您可以编写自己的认证后端使用原始密码:

from django.contrib.auth import backends 
from django.contrib.auth.models import User 

class RawPasswordUser(User): 
    class Meta: 
     proxy = True 

    def set_password(self, raw_password): 
     # default implementation made a hash from raw_password, 
     # we don't want this 
     self.password = raw_password 

    def check_password(self, raw_password): 
     # same here, don't make hash out of raw_password 
     return self.password == raw_password 

class ModelBackend(backends.ModelBackend): 
    def authenticate(self, username=None, password=None): 
     try: 
      user = RawPasswordUser.objects.get(username=username) 
      if user.check_password(password): 
       return user 
     except RawPasswordUser.DoesNotExist: 
      return None 

    def get_user(self, user_id): 
     try: 
      return RawPasswordUser.objects.get(pk=user_id) 
     except RawPasswordUser.DoesNotExist: 
      return None 

在设置文件:

AUTHENTICATION_BACKENDS = (
    # ModelBackend from project_root/auth/backends.py 
    'auth.backends.ModelBackend', 
) 

现在,当你authenticate用户在你的意见,你会得到RawPasswordUser实例。 login_required修饰符同样适用,request.user将指向代理类。

有关详细信息,请参见documentation

对于Django 1.5+ there is also an option用自定义模型替换默认用户模型,但为了保留现有用户,您必须以某种方式迁移它们,请参阅this question


其实你不能保持用户密码不变。

通过以下格式默认的Django存储密码:

算法$迭代$盐$哈希

这意味着:

  • 你不能再生的密码从原件的散列,因为你没有原件。

  • 如果不知道salt,您也将无法在客户端生成相同的散列。你可以将它传递给客户端,但盐应该是一个秘密,所以通过未加密的通道来做是不明智的。

,我看到的最简单的解决办法是保持目前的Django的行为,被Tadeck的意见建议,增加对散列客户端,并强制用户更改他们的密码。

好吧,这不是一个真正的解决方案,因为攻击者可以截取消化的密码并直接使用它们,但是您提到了它的问题更新。既然你不关心安全性,你也可以在JavaScript中检出public key encryption


通过Tadeck提出的另一种解决方案是使用OAuth般的服务,这可能看起来有点像这样:

def index(request): 
    access_token = request.REQUEST.get('token', None) 
    if not access_token: 
     return redirect('login') 

    # Custom authentication backend that accepts a token 
    # and searches for a user with that token in database. 
    user = authenticate(access_token) 
    if not user: 
     return redirect('login') 

    return render(...) 

def auth(request): 
    ''' This ajax-view has to be encrypted with SSL.''' 
    # Normal Django authentication. 
    user = authenticate(request.POST['username'], request.POST['password']) 

    # Authentication failed 
    if user is None: 
     return json.dumps({'error': '...'}) 

    # generate, save and return token in json response 
    token = UserToken(user=user, value=generate_token()) 
    # token.expires_at = datetime.now() + timedelta(days=1) 
    token.save() 

    return json.dumps({'token': token.value}) 

的攻击仍然可以拦截访问令牌,但它是一个有点比拦截更好密码哈希。

+0

我会把'except'放在'user = User.objects.get(...)'的下面' – 2013-05-02 15:28:50

+0

是否需要更改当前的后端记录?我的意思是当使用这个新的后端时,当前用户应该改变他们的密码?我可以写一些脚本来转换它们吗? – GhaghaSibil 2013-05-02 15:41:29

+0

密码将保持哈希,你的客户端发送相同的哈希值,那么你不需要转换任何东西。如果哈希值不同,则可以在'python manage.py shell'中进行转换,导入'django.contrib.auth.models.User'并根据需要进行修改。 – gatto 2013-05-02 15:47:25