I’m using Flask-Security in a Flask project. Basically everything works, until I try to turn on password encryption. Basically I followed this: http://packages.python.org/Flask-Security/configuration.html
Which led to me adding this:
app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt'
app.config['SECURITY_PASSWORD_SALT'] = '$2a$16$PnnIgfMwkOjGX4SkHqSOPO'
This results in a error unfortunately:
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
rv = self.dispatch_request()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1344, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/decorators.py", line 171, in wrapper
return f(*args, **kwargs)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/views.py", line 72, in login
if form.validate_on_submit():
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_wtf/form.py", line 123, in validate_on_submit
return self.is_submitted() and self.validate()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/forms.py", line 165, in validate
if not verify_password(self.password.data, self.user.password):
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/utils.py", line 84, in verify_password
return _pwd_context.verify(get_hmac(password), password_hash)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 2534, in verify
record = self._get_or_identify_record(hash, scheme, category)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 2258, in _get_or_identify_record
return self._identify_record(hash, category)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 1455, in identify_record
raise ValueError("hash could not be identified")
ValueError: hash could not be identified
I’m rather clueless as to what’s happening. I thought i generated a good bcrypt hash, but there are no real examples on the website for password encryption and the error itself confuses me :/
Software used:
— Ubuntu 12.04LTS
— Python 2.7.2
— FLask 0.9
— Flask-Security 1.5.4
— Running on MongoDB 2.2 through MongoAlchemy
Thanks for your help!!
Edit: thanks to Bikeshedder, this is the likely culprit:
# Create a user to test with
@app.before_first_request
def create_user():
user_datastore.create_user(email='test@test.net', password='testerdetest')
I assumed that the create_user method would automatically encrypt the password. But apparently it doesn’t… The documentation isn’t really clear here:
Class flask_security.datastore.MongoEngineUserDatastore(db, user_model, role_model)
A MongoEngine datastore implementation for Flask-Security that assumes the use of the Flask-MongoEngine extension.
create_user(**kwargs)
Creates and returns a new user from the given parameters.
Edit 2: Working further on BikeShedder’s suggestion, I changed my standard user creation to this:
# Create a user to test with
@app.before_first_request
def create_user():
user_datastore.create_user(email='test@test.net', password=bcrypt.hashpw('testerdetest', app.config['SECURITY_PASSWORD_SALT'])
So that solves the error, but it gives me an «Invalid password», meaning that flask-security does something different than I do in my encrypting… argh!
Edit 3: changed from bcrypt to passlib (which flask-security also uses)
app.config['SECURITY_PASSWORD_SALT'] = '/2aX16zPnnIgfMwkOjGX4S'
and
user_datastore.create_user(email='test@test.net', password=passlib.hash.bcrypt.encrypt('testerdetest', salt=app.config['SECURITY_PASSWORD_SALT']))
still get an invalid pw
If i look at the source code at https://github.com/mattupstate/flask-security/blob/develop/flask_security/utils.py it seems it only uses a sha512 encryption… I don’t understand the documentation then…
Edit 5: solved (thanks for putting me on the right direction!)
flask.ext.security.utils.encrypt_password() did the trick. However, i’m still in doubt whether it really is bcrypt or not, but okay, it’s encrypted at least…
I’m using passwords generated by ppc-gen-password
something like $6$rounds=662480$eD9ewKeo67GHU8KF$bwPiwMy90zjvC5AuN27lBLP5Q3uKZOxX.wswfuVOMG0rntdLqM082XbtKh6UnG.bexmqmftJiGnoZGYy2opEf/
which is a hash for changeme
And I’m getting this error:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/pyramid/router.py", line 223, in __call__
response = self.invoke_subrequest(request, use_tweens=True)
File "/usr/local/lib/python2.7/site-packages/pyramid/router.py", line 198, in invoke_subrequest
response = handle_request(request)
File "/usr/local/lib/python2.7/site-packages/pyramid/tweens.py", line 20, in excview_tween
response = handler(request)
File "/usr/local/lib/python2.7/site-packages/pyramid_tm/__init__.py", line 101, in tm_tween
reraise(*exc_info)
File "/usr/local/lib/python2.7/site-packages/pyramid_tm/__init__.py", line 83, in tm_tween
response = handler(request)
File "/usr/local/lib/python2.7/site-packages/pyramid/router.py", line 145, in handle_request
view_name
File "/usr/local/lib/python2.7/site-packages/pyramid/view.py", line 541, in _call_view
response = view_callable(context, request)
File "/usr/local/lib/python2.7/site-packages/pyramid/config/views.py", line 602, in __call__
return view(context, request)
File "/usr/local/lib/python2.7/site-packages/pyramid/config/views.py", line 328, in attr_view
return view(context, request)
File "/usr/local/lib/python2.7/site-packages/pyramid/config/views.py", line 304, in predicate_wrapper
return view(context, request)
File "/usr/local/lib/python2.7/site-packages/pyramid/config/views.py", line 353, in rendered_view
result = view(context, request)
File "/usr/local/lib/python2.7/site-packages/pyramid_duh/params.py", line 306, in param_twiddler
return fxn(**scope)
File "/usr/local/lib/python2.7/site-packages/pypicloud/views/login.py", line 33, in do_login
if request.access.verify_user(username, password):
File "/usr/local/lib/python2.7/site-packages/pypicloud/access/base.py", line 230, in verify_user
return bool(stored_pw and pwd_context.verify(password, stored_pw))
File "/usr/local/lib/python2.7/site-packages/passlib/context.py", line 2553, in verify
record = self._get_or_identify_record(hash, scheme, category)
File "/usr/local/lib/python2.7/site-packages/passlib/context.py", line 2260, in _get_or_identify_record
return self._identify_record(hash, category)
File "/usr/local/lib/python2.7/site-packages/passlib/context.py", line 1457, in identify_record
raise ValueError("hash could not be identified")
Any additional configuration I need to specify in my .ini file?
Я использую Flask-Security в проекте Flask. В основном все работает, пока я не пытаюсь включить шифрование пароля. В основном я следовал этому: http://packages.python.org/Flask-Security/configuration.html
Что привело к тому, что я добавил это:
app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt'
app.config['SECURITY_PASSWORD_SALT'] = '$2a$16$PnnIgfMwkOjGX4SkHqSOPO'
К сожалению, это приводит к ошибке:
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
rv = self.dispatch_request()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1344, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/decorators.py", line 171, in wrapper
return f(*args, **kwargs)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/views.py", line 72, in login
if form.validate_on_submit():
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_wtf/form.py", line 123, in validate_on_submit
return self.is_submitted() and self.validate()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/forms.py", line 165, in validate
if not verify_password(self.password.data, self.user.password):
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/utils.py", line 84, in verify_password
return _pwd_context.verify(get_hmac(password), password_hash)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 2534, in verify
record = self._get_or_identify_record(hash, scheme, category)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 2258, in _get_or_identify_record
return self._identify_record(hash, category)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 1455, in identify_record
raise ValueError("hash could not be identified")
ValueError: hash could not be identified
Я довольно невежественен относительно того, что происходит. Я думал, что сгенерировал хороший хэш bcrypt, но на сайте нет реальных примеров шифрования паролей, и сама ошибка меня смущает :/
Используемое программное обеспечение: — Ubuntu 12.04LTS — Python 2.7.2 — FLask 0.9 — Flask-Security 1.5.4 — Запуск на MongoDB 2.2 через MongoAlchemy
Спасибо за вашу помощь!
Редактировать: благодаря Bikeshedder, это вероятный виновник:
# Create a user to test with
@app.before_first_request
def create_user():
user_datastore.create_user(email='test@test.net', password='testerdetest')
Я предполагал, что метод create_user автоматически зашифрует пароль. Но, видимо, это не так… Документация здесь не совсем ясна:
Class flask_security.datastore.MongoEngineUserDatastore(db, user_model, role_model)
A MongoEngine datastore implementation for Flask-Security that assumes the use of the Flask-MongoEngine extension.
create_user(**kwargs)
Creates and returns a new user from the given parameters.
Редактировать 2: Продолжая работать над предложением BikeShedder, я изменил свое стандартное создание пользователя на это:
# Create a user to test with
@app.before_first_request
def create_user():
user_datastore.create_user(email='test@test.net', password=bcrypt.hashpw('testerdetest', app.config['SECURITY_PASSWORD_SALT'])
Так что это устраняет ошибку, но выдает мне «Неверный пароль», что означает, что flask-security делает что-то другое, чем я делаю при шифровании… ааа!
Редактировать 3: изменено с bcrypt на passlib (которое также использует flask-security)
app.config['SECURITY_PASSWORD_SALT'] = '/2aX16zPnnIgfMwkOjGX4S'
и
user_datastore.create_user(email='test@test.net', password=passlib.hash.bcrypt.encrypt('testerdetest', salt=app.config['SECURITY_PASSWORD_SALT']))
все еще получаю недопустимый pw Если я посмотрю исходный код на https://github.com/mattupstate/flask-security/blob/develop/flask_security/utils.py кажется, он использует только шифрование sha512… Тогда я не понимаю документацию…
Изменить 5: решено (спасибо, что указали мне правильное направление!) flask.ext.security.utils.encrypt_password() сделал свое дело. Тем не менее, я все еще сомневаюсь, действительно ли это bcrypt или нет, но ладно, он хотя бы зашифрован…
У меня есть необходимость проверить хэши паролей, сгенерированные с помощью Python passlib. Моя цель — использовать Passlib’s pbkdf2_sha512
Схема хеширования всех пользовательских паролей. Тем не менее, из-за природы нашего бэкэнда, мне нужно проверить этот пароль из скриптов php, js и java. Ни в одной из них я не нашел библиотек, которые могли бы взять хеш passlib и проверить пароль. Мне было интересно, существует ли такой, прежде чем я решил реализовать алгоритм хэширования passlib в php, js и java.
2
Решение
В Passlib формат хеша pbkdf2_sha256 настраивается для passlib, поэтому (вероятно?) Будет не так много его портов на другие языки. Но это очень простая оболочка для алгоритма PBKDF2-HMAC-SHA256 + кодирование base64, оба из которых являются стандарт и должен иметь реализации для других языков — так что это должно быть довольно легко портировать.
Однако, если переносимость является приоритетным требованием, вы можете попробовать использовать passlib Bcrypt или же sha256_crypt вместо этого хэши Оба из них являются стандартными и должны иметь реализации на нескольких языках.
Имейте в виду, оба bcrypt & sha256_crypt довольно сложны — поэтому, если вы не можете найти порт под одним из нужных вам языков, портирование pbkdf2_sha256 будет ОЧЕНЬ меньшим усилием, чем перенос одного из них.
Другой вариант — вызвать passlib под python через подпроцесс.
Вызов следующего питона oneliner …
python3 -c 'import sys; from passlib.hash import pbkdf2_sha256 as ph; print(ph.verify(input(), input()))'
… позволит тебе написать passwordnhashn
в stdin, и пусть ответит True
или же False
(или сообщение об ошибке, если хеш сформирован неправильно).
Поскольку пароль пишется через stdin, он должен быть относительно безопасным (по сравнению с передачей его в качестве аргумента или env var).
(Эквивалент Python2 такой же, просто используйте raw_input()
вместо input()
)
2
Другие решения
Я могу предложить это решение для PHP:
/*
* This function creates a passlib-compatible pbkdf2 hash result. Parameters are:
* $algo - one of the algorithms supported by the php `hash_pbkdf2()` function
* $password - the password to hash, `hash_pbkdf2()` format
* $salt - a random string in ascii format
* $iterations - the number of iterations to use
*/
function create_passlib_pbkdf2($algo, $password, $salt, $iterations)
{
$hash = hash_pbkdf2($algo, $password, base64_decode(str_replace(".", "+", $salt)), $iterations, 64, true);
return sprintf("$pbkdf2-%s$%d$%s$%s", $algo, $iterations, $salt, str_replace("+", ".", rtrim(base64_encode($hash), '=')));
}
Если вы скопируете соль, итерации и алгоритм из существующей хеш-строки, сгенерированной passlib, и передадите им открытый текстовый пароль для этой функции, он сгенерирует тот же результат, что и passlib.
Вот функция php для проверки пароля passlib pbkdf2 на основе вышеизложенного:
/*
* This function verifies a python passlib-format pbkdf2 hash against a password, returning true if they match
* only ascii format password are supported.
*/
function verify_passlib_pbkdf2($password, $passlib_hash)
{
if (empty($password) || empty($passlib_hash)) return false;
$parts = explode('$', $passlib_hash);
if (!array_key_exists(4, $parts)) return false;
/*
* Results in:
* Array
* (
* [0] =>
* [1] => pbkdf2-sha512
* [2] => 20000
* [3] => AGzdiek7yUzJ9iorZD6dBPdy
* [4] => 0298be2be9f2a84d2fcc56d8c88419f0819c3501e5434175cad3d8c44087866e7a42a3bd170a035108e18b1e296bb44f0a188f7862b3c005c5971b7b49df22ce
* )
*/
$t = explode('-', $parts[1]);
if (!array_key_exists(1, $t)) return false;
$algo = $t[1];
$iterations = (int) $parts[2];
$salt = $parts[3];
$orghash = $parts[4];
$hash = create_passlib_pbkdf2($algo, $password, $salt, $iterations);
return $passlib_hash === $hash;
}
2
В Java вы можете использовать Jython, который позволяет использовать библиотеки Python и выполнять код Python.
Вот пример java-функции для проверки хеша с использованием passlib:
Boolean verify_pbkdf2_sha512(String pw, String hash) {
PythonInterpreter python = new PythonInterpreter();
python.exec("from passlib.hash import pbkdf2_sha512");
python.set("pw", new PyString(pw));
python.set("hash", new PyString(hash));
python.exec("valid = 1 if pbkdf2_sha512.identify(hash) and pbkdf2_sha512.verify(pw, hash) else 0");
Boolean valid = ((PyInteger)python.get("valid")).asInt()==1;
return (Boolean)valid;
}
Вы можете найти больше информации в моем блоге: http://codeinpython.blogspot.com/2015/11/using-python-passlib-in-java.html
-2