Я попытался реализовать аутентификацию на основе отпечатков пальцев с помощью пакета Python DUO-lab webauthn
. Однако я столкнулся с этой ошибкой:
server validation of credential failed: registration failed. error: registration rejected. error: unable to verify origin..
Когда я проверил исходный код пакета, я заметил, что эта ошибка unable to verify origin..
возникла, когда, возможно, ваш аутентификатор был неправильно настроен.
Могу ли я конкретно указать, что мне нужны только аутентификаторы platform
, а не roaming
, не загромождая исходный код пакета? Если есть, пожалуйста, включите полный рабочий код для Flask
(это то, что я использую сейчас после того, как ошибка выгнала меня из Django). Мои текущие конфигурации:
RP_ID = 'nacesdecide.herokuapp.com' #The app is currently hosted on heroku
RP_NAME = 'nacesdecides nacesdecide'
ORIGIN = 'https://nacesdecide.herokuapp.com/'
Приложение в настоящее время находится на сайте heroku, и к нему можно получить доступ в режиме реального времени через регистр naces. Я хочу, чтобы приложение использовало только platform authenticators
.
Обновление:
Некоторая часть кода на стороне клиента (взято из python webauthn flask demon js от duo-lab:
/**
* REGISTRATION FUNCTIONS
*/
/**
* Callback after the registration form is submitted.
* @param {Event} e
*/
const didClickRegister = async (e) => {
e.preventDefault();
// gather the data in the form
const form = document.querySelector("#register-form");
const formData = new FormData(form);
// post the data to the server to generate the PublicKeyCredentialCreateOptions
let credentialCreateOptionsFromServer;
try {
credentialCreateOptionsFromServer = await getCredentialCreateOptionsFromServer(
formData
);
} catch (err) {
showErrorAlert(`Failed to generate credential request options: ${err}`);
return console.error("Failed to generate credential request options:", err);
}
// convert certain members of the PublicKeyCredentialCreateOptions into
// byte arrays as expected by the spec.
const publicKeyCredentialCreateOptions = transformCredentialCreateOptions(
credentialCreateOptionsFromServer
);
// request the authenticator(s) to create a new credential keypair.
let credential;
*try {
credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreateOptions,
});*
} catch (err) {
showErrorAlert(`Error creating credential: ${err}`);
return console.error("Error creating credential:", err);
}
// we now have a new credential! We now need to encode the byte arrays
// in the credential into strings, for posting to our server.
const newAssertionForServer = transformNewAssertionForServer(credential);
// post the transformed credential data to the server for validation
// and storing the public key
let assertionValidationResponse;
try {
assertionValidationResponse = await postNewAssertionToServer(
newAssertionForServer
);
} catch (err) {
showErrorAlert(`Server validation of credential failed: ${err}`);
return console.error("Server validation of credential failed:", err);
}
// reload the page after a successful result
setTimeout(function () {
window.location.href = Flask.url_for("accounts.login");
}, 1000);
// window.location.reload();
};
На стороне сервера у нас есть:
def webauthn_begin_activate():
# MakeCredentialOptions
username = request.form.get('register_username')
display_name = request.form.get('register_display_name')
if not util.validate_username(username):
return make_response(jsonify({'fail': 'Invalid username.'}), 401)
if not util.validate_display_name(display_name):
return make_response(jsonify({'fail': 'Invalid display name.'}), 401)
if User.query.filter_by(username=username).first():
return make_response(jsonify({'fail': 'User already exists.'}), 401)
#clear session variables prior to starting a new registration
session.pop('register_ukey', None)
session.pop('register_username', None)
session.pop('register_display_name', None)
session.pop('challenge', None)
session['register_username'] = username
session['register_display_name'] = display_name
challenge = util.generate_challenge(32)
ukey = util.generate_ukey()
# We strip the saved challenge of padding, so that we can do a byte
# comparison on the URL-safe-without-padding challenge we get back
# from the browser.
# We will still pass the padded version down to the browser so that the JS
# can decode the challenge into binary without too much trouble.
session['challenge'] = challenge.rstrip('=')
session['register_ukey'] = ukey
*make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
challenge, RP_NAME, RP_ID, ukey, username, display_name,
'https://example.com')*
return jsonify(make_credential_options.registration_dict)
Эта функция также может быть интересна:
def verify_credential_info():
challenge = session['challenge']
username = session['register_username']
display_name = session['register_display_name']
ukey = session['register_ukey']
registration_response = request.form
trust_anchor_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)), TRUST_ANCHOR_DIR)
trusted_attestation_cert_required = True
self_attestation_permitted = True
none_attestation_permitted = True
webauthn_registration_response = webauthn.WebAuthnRegistrationResponse(
RP_ID,
ORIGIN,
registration_response,
challenge,
trust_anchor_dir,
trusted_attestation_cert_required,
self_attestation_permitted,
none_attestation_permitted,
uv_required=False) # User Verification
try:
webauthn_credential = webauthn_registration_response.verify()
except Exception as e:
return jsonify({'fail': 'Registration failed. Error: {}'.format(e)})
# Step 17.
#
# Check that the credentialId is not yet registered to any other user.
# If registration is requested for a credential that is already registered
# to a different user, the Relying Party SHOULD fail this registration
# ceremony, or it MAY decide to accept the registration, e.g. while deleting
# the older registration.
credential_id_exists = User.query.filter_by(
credential_id=webauthn_credential.credential_id).first()
if credential_id_exists:
return make_response(
jsonify({
'fail': 'Credential ID already exists.'
}), 401)
existing_user = User.query.filter_by(username=username).first()
if not existing_user:
if sys.version_info >= (3, 0):
webauthn_credential.credential_id = str(
webauthn_credential.credential_id, "utf-8")
webauthn_credential.public_key = str(
webauthn_credential.public_key, "utf-8")
user = User(
ukey=ukey,
username=username,
display_name=display_name,
pub_key=webauthn_credential.public_key,
credential_id=webauthn_credential.credential_id,
sign_count=webauthn_credential.sign_count,
rp_id=RP_ID,
icon_url='https://example.com')
db.session.add(user)
db.session.commit()
else:
return make_response(jsonify({'fail': 'User already exists.'}), 401)
flash('Successfully registered as {}.'.format(username))
return jsonify({'success': 'User successfully registered.'})
Второе обновление. Ниже приведен полный журнал:
webauthn.js:101
{id: "ATdDPQneoYF3tA6HYW8_dr2eBDy53VNoEIHRWUDfnmT2URKIs0SQ_lQ7BujdmcfM9Hc2xNH8bvLf4k3lQJ-7RX4",
rawId: "ATdDPQneoYF3tA6HYW8_dr2eBDy53VNoEIHRWUDfnmT2URKIs0SQ_lQ7BujdmcfM9Hc2xNH8bvLf4k3lQJ-7RX4",
type: "public-key",
attObj: "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjFD32HDgTSvc6zIlggmLLxXTKQyiabSwuLWNiTpJ3WQfmMoC_qX_QTuWPWHo4",
clientData: "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIj9pZFBhY2thZ2VOYW1lIjoiY29tLmFuZHJvaWQuY2hyb21lIn0", …}
attObj: "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjFD32HDgTSvcJxUiUIT6ViS4biCWKTR25PIW3beO9V5NdFAAAAALk_2WHy5kYvsSKCACJH3ngAQQE3Qz0J3qGBd7QOh2FvP3a9ngQ8ud1TaBCB0VlA355k9lESiLNEkP5UOwbo3ZnHzPR3NsTR_G7y3-JN5UCfu0V-pQECAyYgASFYID93HTRf5UtMsCsW9D5TyWQDSgMW2MDhiYWKnz3sq16zIlggmLLxXTKQyiabSwuLWNiTpJ3WQfmMoC_qX_QTuWPWHo4"
clientData: "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoidFNOS3g5RnVyWFI4dlhVdVBkVms5azhDcEhlMWMydnlrbkdwYUhseXZKYyIsIm9yaWdpbiI6Imh0dHBzOlwvXC9uYWNlc2RlY2lkZS5oZXJva3VhcHAuY29tIiwiYW5kcm9pZFBhY2thZ2VOYW1lIjoiY29tLmFuZHJvaWQuY2hyb21lIn0"
id: "ATdDPQneoYF3tA6HYW8_dr2eBDy53VNoEIHRWUDfnmT2URKIs0SQ_lQ7BujdmcfM9Hc2xNH8bvLf4k3lQJ-7RX4"
rawId: "ATdDPQneoYF3tA6HYW8_dr2eBDy53VNoEIHRWUDfnmT2URKIs0SQ_lQ7BujdmcfM9Hc2xNH8bvLf4k3lQJ-7RX4"
registrationClientExtensions: "{}"
type: "public-key"__proto__: Object
webauthn.js:107 Server validation of credential failed: Registration failed. Error: Registration rejected. Error: Unable to verify origin..
didClickRegister @ webauthn.js:107
async function (async)
didClickRegister @ webauthn.js:68
1 ответ
Я думаю, проблема в том, что у вашего значения ORIGIN
стоит косая черта.
пиринг в cliendDataJSON формирующего ответ аттестационной в , происхождение сообщается как "https://nacesdecide.herokuapp.com"
:
Response: "https://nacesdecide.herokuapp.com"
ORIGIN: "https://nacesdecide.herokuapp.com/"
Если вы удалите косую черту в конце, я уверен, что все будет проверено, как ожидалось.
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.