在Eve中,如何安全地存储用户密码?

时间:2014-11-20 00:49:55

标签: python eve

如果在运行文件中放置调试器,您将看到用户密码被哈希,但是当您查看mongo集合时,用户的密码将以纯文本格式存储。如何将用户密码保存为哈希?

以下是我的文件:

run.py:

from eve import Eve
from eve.auth import BasicAuth

import bcrypt

class BCryptAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        # use Eve's own db driver; no additional connections/resources are used
        accounts = app.data.driver.db["accounts"]
        account = accounts.find_one({"username": username})
        return account and \
            bcrypt.hashpw(password, account['password']) == account['password']

def create_user(*arguments, **keywords):
    password = arguments[0][0]['password']
    username = arguments[0][0]['username']
    user = {
        "password": bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()),
        "username": username,
    }
    return post_internal("accounts", user)


app = Eve(auth=BCryptAuth)
app.on_insert_accounts += create_user

if __name__ == '__main__':
    app.run()

settings.py:

API_NAME = "gametest"

CACHE_CONTROL = "max-age=20"
CACHE_EXPIRES = 20
MONGO_DBNAME = "gametest"
MONGO_HOST = "localhost"
MONGO_PORT = 27017
PUBLIC_ITEM_METHODS = ["GET"]
RESOURCE_METHODS = ["GET"]

accounts_schema = {
    "username": {
        "type": "string",
        "required": True,
        "unique": True,
    },
    "password": {
        "type": "string",
        "required": True,
    },
}

accounts = {
    # the standard account entry point is defined as
    # '/accounts/<ObjectId>'. We define  an additional read-only entry
    # point accessible at '/accounts/<username>'.
    "additional_lookup": {
        "url": "regex('[\w]+')",
        "field": "username",
    },

    # We also disable endpoint caching as we don't want client apps to
    # cache account data.
    "cache_control": "",
    "cache_expires": 0,

    # Finally, let's add the schema definition for this endpoint.
    "schema": accounts_schema,
    "public_methods": ["POST"],
    "resource_methods": ["POST"],
}
games_schema = {
    "game_id": {
        "type": "objectid",
        "required": True
    },
    "title": {
        "type": "string",
        "required": True
    },
}

games = {
    "item_title": "game",
    "schema": games_schema,
}

orders = {
    "schema": {
        "game": {
            "type": "objectid",
            "required": True,
        },
    },
    "resource_methods": ["GET", "POST"],
}

DOMAIN = {
    "accounts", accounts,
    "orders": orders,
    "games": game,
}

2 个答案:

答案 0 :(得分:3)

run.py中的一些主要内容阻止您进行身份验证:

  • 在您的create_user事件挂钩中,您使用bcrypt.gensalt()生成了一个盐,但您无法在任何地方保存盐。 Salts对于防止rainbow table攻击非常有用,但您需要保存它们,以便在尝试再次对密码进行哈希处理时获得相同的结果。
  • 您使用on_insert_accounts事件挂钩在文档发布之前修改文档,但随后返回post_internal而不是让事件挂钩运行。这个可能有效,但我觉得你应该按照预期使用事件钩子。

以下是修改后的run.py

from eve import Eve
from eve.auth import BasicAuth

import bcrypt

class BCryptAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        # use Eve's own db driver; no additional connections/resources are used
        accounts = app.data.driver.db["accounts"]
        account = accounts.find_one({"username": username})
        return account and \
            bcrypt.hashpw(password.encode('utf-8'), account['salt'].encode('utf-8')) == account['password']

def create_user(documents):
    for document in documents:
        document['salt'] = bcrypt.gensalt().encode('utf-8')
        password = document['password'].encode('utf-8')
        document['password'] = bcrypt.hashpw(password, document['salt'])

app = Eve(auth=BCryptAuth)
app.on_insert_accounts += create_user

if __name__ == '__main__':
    app.run()

您的settings.py中存在一些拼写错误,所以我在这里提供了一个可行的版本以便进行测量:

API_NAME = "gametest"

CACHE_CONTROL = "max-age=20"
CACHE_EXPIRES = 20
MONGO_DBNAME = "gametest"
MONGO_HOST = "localhost"
MONGO_PORT = 27017
PUBLIC_ITEM_METHODS = ["GET"]
RESOURCE_METHODS = ["GET"]

accounts_schema = {
    "username": {
        "type": "string",
        "required": True,
        "unique": True
    },
    "password": {
        "type": "string",
        "required": True
    }
}

accounts = {
    # the standard account entry point is defined as
    # '/accounts/<ObjectId>'. We define  an additional read-only entry
    # point accessible at '/accounts/<username>'.
    "additional_lookup": {
        "url": "regex('[\w]+')",
        "field": "username",
    },

    # We also disable endpoint caching as we don't want client apps to
    # cache account data.
    "cache_control": "",
    "cache_expires": 0,

    # Finally, let's add the schema definition for this endpoint.
    "schema": accounts_schema,
    "public_methods": ["POST"],
    "resource_methods": ["POST"]
}
games_schema = {
    "game_id": {
        "type": "objectid",
        "required": True
    },
    "title": {
        "type": "string",
        "required": True
    }
}

games = {
    "item_title": "game",
    "schema": games_schema
}

orders = {
    "schema": {
        "game": {
            "type": "objectid",
            "required": True,
        }
    },
    "resource_methods": ["GET", "POST"]
}

DOMAIN = {
    "accounts": accounts,
    "orders": orders,
    "games": games
}

答案 1 :(得分:0)

我做了这样的事情,以安全地存储我的用户密码,并阻止没有授权密钥的管理员创建:

class TokenAuthCutom(TokenAuth):
    def check_auth(self, token, allowed_roles, resource, method):
        payload = decode_token(token)
        # check if payload is valid and if allowed_roles is not empty check if role is valid
        return payload and (not allowed_roles or payload['roles'] in allowed_roles)

def before_insert_user(documents):
    body = request.get_json(force=True)
    admin_key = body.get('admin_register_key')
    for document in documents:
        password = document['password'].encode('utf-8')
        document['password'] = bcrypt.hashpw(password, bcrypt.gensalt()).decode('utf-8')
        document['roles'] = 'admin' if admin_key is not None and admin_key == ADMIN_REGISTER_KEY else 'client'


if __name__ == '__main__':
    app = Eve(auth=TokenAuthCutom)
    app.on_insert_users += before_insert_user
    app.run(host=HOST, port=PORT)