justinmayer / kagi

WebAuthn security keys and TOTP multi-factor authentication for Django
BSD 2-Clause "Simplified" License
91 stars 10 forks source link

util.get_origin scheme causes JS SecurityError when Django is behind a proxy #46

Closed johnmcc3 closed 2 years ago

johnmcc3 commented 2 years ago

When fetching the origin for the webauthn module, the get_origin function relies on the scheme returned by the Django request object. This is fine for local development, but if Django is served through a proxy that upgrades the connection to https, the upgrade is not reflected in the scheme attribute.

In this case, the user is accessing the site through https, but the webauthn module is still told the connection is happening through http, causing the DOMException / SecurityError: “The operation is insecure.” error to be thrown.

Perhaps the request object’s is_secure() method should be used instead of the scheme? Happy to submit a PR if this sounds good.

justinmayer commented 2 years ago

Thanks for the detailed information, John. Two quick questions:

johnmcc3 commented 2 years ago

Proxy is apache/httpd, Django server is uWSGI.

justinmayer commented 2 years ago

Perhaps the request object’s is_secure() method should be used instead of the scheme?

If you look at the is_secure() function's source code, you'll see that all it does is check whether request.scheme == 'https', and if so, the function returns True. So I don't see how using the is_secure() function would help resolve the issue described here. Maybe I am missing something?

Meanwhile, let's make sure your server/app configuration settings are taking the proxy into account. Could you try adding the following to the respective configuration files?

Apache Configuration

RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
RequestHeader set X-Forwarded-SSL expr=%{HTTPS}

Django Settings: Add SECURE_PROXY_SSL_HEADER

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

After you make the above additions and restart all services, do you still see the same error?

johnmcc3 commented 2 years ago

Whoops, good catch on the is_secure() function. Also, that combination of apache/django settings got it working! Thanks for the help, glad it was just a config issue on my side 😃