Не удается зарегистрировать ключ U2F с помощью API-интерфейсов javascript и python

#javascript #django #fido-u2f

#javascript #django #fido-u2f

Вопрос:

Я пытаюсь реализовать устройства аутентификации U2F в моем приложении django. Основная проблема сейчас заключается в том, что все мои интерфейсные вызовы регистрации завершаются с ошибкой.

Я использую u2f-api.js скрипт и скрипт python-u2flib-server python для реализации этого.

Я следую этому шаблону:

1) Сгенерируйте ключ / вызов с помощью u2flib

 from u2flib_server import u2f
app_id = 'https://127.0.0.1'
reg = u2f.begin_registration(app_id)
print reg 
# {'registeredKeys': [], 
   'registerRequests': [{'challenge': u'pLzGmABMwBzQkco6INeFNuPsAG6KhgfVeYFeV0QBf1g', version': 'U2F_V2'}], 
   'appId': 'https://127.0.0.1'}
 

2) Зарегистрируйте ключ из браузера

 var reg_data = {'registeredKeys': [], 'registerRequests': [{'challenge': 'pLzGmABMwBzQkco6INeFNuPsAG6KhgfVeYFeV0QBf1g', 'version': 'U2F_V2'}], 'appId': 'https://127.0.0.1'}

u2f.register(reg_data['appId'], reg_data['registerRequests'], [], function(resp) { console.log(resp) });
 

Это последовательно возвращает {errorCode: 2} ответ, что по сути означает неверный запрос. Однако я не могу определить, какая часть этого запроса недействительна.

Я использую runserver_plus --cert certname для запуска свой локальный веб-сервер, чтобы сайт обслуживался через HTTPS. Я также пытался использовать NGROK для доступа к своему сайту по протоколу HTTPS и попытался использовать тот же код. Я постоянно получаю один и тот же ответ.

Я был бы признателен за любую помощь, указания или рекомендации по моей реализации, поскольку я боролся в течение нескольких дней, а существующая документация по библиотекам и реализациям U2F довольно скудная.

— Обновить —

Я действительно добился здесь небольшого прогресса. Я могу получить ответ «сгенерировать ключ». Однако я по-прежнему не могу зарегистрировать этот ключ в библиотеке python.

В итоге у меня получается что-то вроде этого на стороне сервера:

 response = {'challenge': 'okGbjnbE2V9cT42X2wm-PA9pm7k3KpTETVEv2SqEUxE', 'registrationData': 'BRS5y7dFXs0O60o2cUFc-SZtKG3jibpFQGuwQDyTQkSWeQUNWn\u2026bEwIhALYcM1NospvymAbv83lTlpLjaa2ICSFQv-5RYfzkPCc9', 'version': 'U2F_V2', 'clientData': 'eyJjaGFsbGVuZ2UiOiJva0dianBnRTJWOWNUNDJYMndtLVBBOX\u2026R5cCI6Im5hdmlnYXRvci5pZC5maW5pc2hFbnJvbGxtZW50In0'}

register_request = {'registeredKeys': [], 'registerRequests': [{'challenge': 'okGbjpgE2V9cD32X2wm-PA9pm7k3KpKN5VEv2SqEUxE', 'version': 'U2F_V2'}], 'appId': 'https://127.0.0.1:8000'}

u2f.complete_registration(register_request, response)
 

Однако это приводит к следующей ошибке:

 Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/u2flib_server/u2f.py", line 45, in complete_registration
    return U2fRegisterRequest.wrap(request).complete(response, valid_facets)
  File "/usr/local/lib/python2.7/dist-packages/u2flib_server/model.py", line 419, in complete
    _validate_client_data(resp.clientData, req.challenge, Type.REGISTER,
  File "/usr/local/lib/python2.7/dist-packages/u2flib_server/model.py", line 339, in clientData
    return ClientData.wrap(self['clientData'])
  File "/usr/local/lib/python2.7/dist-packages/u2flib_server/model.py", line 261, in wrap
    return data if isinstance(data, cls) else cls(data)
  File "/usr/local/lib/python2.7/dist-packages/u2flib_server/model.py", line 328, in __init__
    super(ClientData, self).__init__(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/u2flib_server/model.py", line 239, in __init__
    kwargs = json.loads(arg.decode('utf-8'))
  File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 382, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded
 

Я снова застрял! Я пытался создать json-дампы из значений, прежде чем передавать их u2f.register , но безрезультатно — я получаю точно такую же ошибку.

Ответ №1:

После долгих исследований, поиска случайных записей в блогах и множества проб и ошибок я, наконец, смог выполнить эту задачу с помощью вышеупомянутых библиотек. Я опубликую здесь пример того, как я этого добился. Во-первых, убедитесь, что вы используете свой локальный веб-сервер по протоколу https https://localhost:8000 (или любой другой порт, localhost который необходим).

  1. Во-первых, создайте вызов из библиотеки python
      def get(self, request, *args, **kwargs):
         user_devices = [..get user device JSON blobs if they exist, or just blank]
         register_request = u2f.begin_registration('https://127.0.0.1:8000', user_devices)
         # return value to front end 
         return render(request, self.template_name, {
             'register_request': register_request
         })
     
  2. Во внешнем интерфейсе дайте браузеру сигнал начать регистрацию U2F. Это подаст ключу сигнал к готовности. Отправьте результат регистрации в конечную точку завершения регистрации
      registerRequest = {{ register_request | safe }} //json result of above 
     var regReq = {'challenge':registerRequest.challenge, 'version': registerRequest.version}
     window.u2f.register(this.appID, [regReq], [], function(keyAuthResponse) {
         $.ajax({url: '/path-to-registration/', 
                 type: "POST",
                 data: keyAuthResponse, 
                 success: function(res){ console.log('sent verification' }
         })
     })
     
  3. На стороне вашего сервера примите и подтвердите ключ
      data = reg{'challenge': request.POST.get('challenge'),
                'clientData': request.POST.get('clientData'),
                'registrationData': request.POST.get('registrationData'),
                 'version': request.POST.get('version'),
     })
     #You need hte original register request, either in session or elsewhere to fetch
     register_request = request.session.get('_u2f_registration_request')
     device_details, facets =  u2f.complete_registration(register_request, data)
     

complete_registration Если устройство зарегистрировано, оно не вернет никаких ошибок.

Я надеюсь, что это поможет кому-то в будущем.