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

标签 python eve

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

这是我的文件:

运行.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()

设置.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,
}

最佳答案

您的 run.py 中有一些主要问题阻止您进行身份验证:

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

这是修改后的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
}

关于python - 在Eve中,如何安全地存储用户的密码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27029842/

相关文章:

python - Skimage - 调整大小功能的奇怪结果

javascript - JS访问mongoengine后端

python - Python-eve Rest Api 框架中的用户相关资源过滤器

python - python-eve 的多态类型

python - 根据其他列和行的值设置 DataFrame 列的值

python - 在 Python 中识别一维和二维数据中的异常值 block

python - 在用 pybrain 训练的网络中输出总是相等的以逼近函数

Python Eve 从给定文件夹提供静态文件

Python Eve - 使用 objectid 的 where 子句

python - 仅使用字母的名称输入验证