Ошибка при создании passkey пользователя в браузере

Когда я пытаюсь создать парольный ключ на своём сайте, появляется сообщение:

Процесс регистрации парольного ключа истёк по времени, был отменён или не разрешён

Однако я могу создать парольный ключ на форуме Meta Discourse в том же браузере (Microsoft Edge) и с тем же расширением (Apple Passkey).

Я обновил свой Discourse до последней версии, но это не помогло, как в этом посте.

Привет, похоже, что мы действительно показываем ошибку в консоли, когда появляется это сообщение, которое вы поделили, в диалоговом окне.

Не могли бы вы открыть консоль браузера и поделиться с нами ошибкой, которую вы можете увидеть?


Похоже, в логах ничего об этой ошибке нет

Вам нужно посмотреть лог консоли вашего браузера, а не логи сайта /logs.

Это правильно?

forum.beginner.center/:1  Смешанный контент: страница по адресу 'https://forum.beginner.center/' была загружена через HTTPS, но запросила небезопасный шрифт 'http://forum.beginner.center/fonts/JetBrainsMono-Regular.woff2?v=0.0.19'. Этот запрос был заблокирован; контент должен предоставляться через HTTPS.
forum.beginner.center/:1  Смешанный контент: страница по адресу 'https://forum.beginner.center/' была загружена через HTTPS, но запросила небезопасный шрифт 'http://forum.beginner.center/fonts/JetBrainsMono-Bold.woff2?v=0.0.19'. Этот запрос был заблокирован; контент должен предоставляться через HTTPS.
app.js:270 ℹ️ Discourse v3.5.0.beta9-dev — https://github.com/discourse/discourse/commits/33dfd7dba9 — Ember v5.12.0
[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

[Только отчёт] Отказано в оценке строки как JavaScript, поскольку 'unsafe-eval' не является разрешённым источником скрипта в следующей директиве политики безопасности контента: "script-src 'nonce-4YvvTZffYuqGaENC8DnQ7yeNg' 'strict-dynamic'".

analytics.eu.umami.is/script.js:1   Не удалось загрузить ресурс: net::ERR_CONNECTION_CLOSED
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
Предотвращение отслеживания заблокировало доступ к хранилищу для <URL>.
deprecated.js:62  Уведомление о устаревании: Установка свойства timezone объекта пользователя устарела. Используйте объект user_option вместо этого [устарело с версии Discourse 2.9.0.beta12] [удаление в версии Discourse 3.0.0.beta1] [идентификатор устаревания: discourse.user.userOptions]
a @ deprecated.js:62
security:1 Обработка autofocus была заблокирована, поскольку в документе уже есть фокусированный элемент.
completion_list.html:14   GET chrome-extension://mfbcdcnpokpoajjciilocoachedjkima/heuristicsRedefinitions.js net::ERR_FILE_NOT_FOUND
completion_list.html:13   GET chrome-extension://mfbcdcnpokpoajjciilocoachedjkima/extensionState.js net::ERR_FILE_NOT_FOUND
completion_list.html:12   GET chrome-extension://mfbcdcnpokpoajjciilocoachedjkima/utils.js net::ERR_FILE_NOT_FOUND
ajax.js:188   POST https://forum.beginner.center/u/register_passkey.json 401 (Unauthorized)
send @ jquery.js:9940
ajax @ jquery.js:9521
o @ ajax.js:188
(аноним) @ rsvp-DaQAFb0W.js:435
e @ rsvp-DaQAFb0W.js:451
A @ ajax.js:201
registerPasskey @ user.js:650
createPasskey @ user-passkeys.gjs:86
await in createPasskey
didConfirm @ user-passkeys.gjs:140
didConfirmWrapped @ dialog.js:134
_join @ index.js:788
join @ index.js:605
p @ index.js:152
(аноним) @ index.js:250
submit @ confirm-session.gjs:84
await in submit
(аноним) @ d-button.gjs:138
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_later @ index.js:823
later @ index.js:652
T @ index.js:562
_triggerAction @ d-button.gjs:135
click @ d-button.gjs:93
user-passkeys.gjs:104  {jqXHR: {…}, textStatus: 'error', errorThrown: ''}errorThrown: ""jqXHR: abort: ƒ (e)always: ƒ ()catch: ƒ (e)done: ƒ ()fail: ƒ ()getAllResponseHeaders: ƒ ()getResponseHeader: ƒ (e)jqTextStatus: "error"overrideMimeType: ƒ (e)pipe: ƒ ()progress: ƒ ()promise: ƒ (e)readyState: 4requestedUrl: "/u/register_passkey.json"responseJSON: {errors: Array(1)}responseText: "{\"errors\":[\"The origin of the authentication request does not match the server origin.\"]}"setRequestHeader: ƒ (e,t)state: ƒ ()status: 401statusCode: ƒ (e)statusText: "error"then: ƒ (e,i,n)[[Prototype]]: ObjecttextStatus: "error"[[Prototype]]: Objectconstructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()__defineGetter__: ƒ __defineGetter__()__defineSetter__: ƒ __defineSetter__()__lookupGetter__: ƒ __lookupGetter__()__lookupSetter__: ƒ __lookupSetter__()__proto__: (...)get __proto__: ƒ __proto__()set __proto__: ƒ __proto__()
createPasskey @ user-passkeys.gjs:104
await in createPasskey
didConfirm @ user-passkeys.gjs:140
didConfirmWrapped @ dialog.js:134
_join @ index.js:788
join @ index.js:605
p @ index.js:152
(аноним) @ index.js:250
submit @ confirm-session.gjs:84
await in submit
(аноним) @ d-button.gjs:138
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_later @ index.js:823
later @ index.js:652
T @ index.js:562
_triggerAction @ d-button.gjs:135
click @ d-button.gjs:93

Ох, хм, это полезно, но ошибки 401 могут возникать по множеству причин. Проверю с нашим экспертом по ключам доступа.

Убедитесь, что ваш сайт настроен на обслуживание всего трафика через HTTPS. Проверка вызова ключа доступа требует, чтобы все запросы отправлялись через HTTPS. Кроме того, домен между браузером и сервером должен точно совпадать. Если где-то есть несоответствие, проверка не пройдет.

У нас есть настройка force_https, вы можете попробовать её — это может помочь (однако будьте осторожны: если сервер настроен неправильно, это может заблокировать вам доступ).

Вот мой app.yml
Я использую обратный прокси на OpenResty (основан на nginx)

expose:
  - "6180:80"   # http
  - "6443:443" # https
  - "587:587"

Я не могу получить доступ к моему сайту через HTTPS на порту 6443

Поэтому я настроил обратный прокси только для HTTP

Вот моя конфигурация OpenResty:

server {
    listen 80 ; 
    listen 443 ssl http2 ; 
    server_name forum.beginner.center; 
    index index.php index.html index.htm default.php default.htm default.html; 
    proxy_set_header Host $host; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header X-Forwarded-Host $server_name; 
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_http_version 1.1; 
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection $http_connection; 
    access_log /www/sites/forum.beginner.center/log/access.log main; 
    error_log /www/sites/forum.beginner.center/log/error.log; 
    location ^~ /.well-known/acme-challenge {
        allow all; 
        root /usr/share/nginx/html; 
    }
    if ($scheme = http) {
        return 301 https://$host$request_uri; 
    }
    ssl_certificate /www/sites/forum.beginner.center/ssl/fullchain.pem; 
    ssl_certificate_key /www/sites/forum.beginner.center/ssl/privkey.pem; 
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1; 
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED; 
    ssl_prefer_server_ciphers on; 
    ssl_session_cache shared:SSL:10m; 
    ssl_session_timeout 10m; 
    error_page 497 https://$host$request_uri; 
    proxy_set_header X-Forwarded-Proto https; 
    add_header Strict-Transport-Security "max-age=31536000"; 
    include /www/sites/forum.beginner.center/proxy/*.conf; 
}

Вот конфигурация обратного прокси:

location ^~ / {
    proxy_pass http://127.0.0.1:6180; 
    proxy_set_header Host $host; 
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header REMOTE-HOST $remote_addr; 
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection $http_connection; 
    proxy_set_header X-Forwarded-Proto $scheme; 
    proxy_http_version 1.1; 
    add_header X-Cache $upstream_cache_status; 
    add_header Cache-Control no-cache; 
    proxy_ssl_server_name off; 
    proxy_ssl_name $proxy_host; 
    add_header Strict-Transport-Security "max-age=31536000"; 
}

Привет, кто-нибудь может помочь мне?

Извините за задержку. Проблема здесь действительно связана с вашим прокси-сервером. Я не могу точно сказать, в чём дело, но что-то мешает: либо доменное имя, либо протокол (http или https), либо порт.

Passkeys проверяют, что фронтенд и бэкенд работают на одном домене, протоколе и порту. Если хотя бы один из этих параметров не совпадает, вы получите ошибку вроде этой.

В консоли Rails попробуйте выполнить:

DiscourseWebauthn.origin

и сравните результат с URL, который вы используете для доступа к сайту в браузере. Они должны совпадать.

Функция пользовательского passkey сработала, когда я включил force https

ссылка

Насколько я понимаю, стандарт WebAuthn для passkey предполагает безопасное соединение между доверяющей стороной (Discourse), клиентом (браузер или мобильное устройство) и аутентификатором (например, YubiKey). Следовательно, для связи от приложения Discourse требуется использование HTTPS. Принудительное включение HTTPS может стать решением, но, возможно, достаточно будет просто заголовка:

proxy_set_header X-Forwarded-Proto https;

Если принудительное включение HTTPS помогает (что, в любом случае, рекомендуется), то всё в порядке.

Я не знаю, как настроить proxy_set_header X-Forwarded-Proto в app.yaml?