All authentication methods use "Authorization" header, which is unreliable #2512

Closed
mnelson4 opened this Issue May 25, 2016 · 10 comments

Projects

None yet

5 participants

@mnelson4
mnelson4 commented May 25, 2016 edited

From what I can tell, all the authentication methods, except cookie authentication, recommended on http://v2.wp-api.org/guide/authentication/ use the "Authorization" header.
The "Authentcation" header isn't reliably received on all server configurations (see WP-API/Basic-Auth#1, WP-API/Basic-Auth#35, and https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/, see the section on "PHP HTTP Authorization Header enable"). The typical workaround seems to require changing your .htaccess file (although that of course only applies to Apache setups; I'm not sure what nginx setups need to do)

On basic auth plugin, there was this suggestion on an even-less-secure way to pass the username and password: WP-API/Basic-Auth#13. Yuck. But the querystring and request body are more reliable. Or maybe we should just use a different http header for storing authentication data?Thoughts on this?

@mnelson4

Oh and I asked a similar issue on the application passwords repo: georgestephanis/application-passwords#46, no discussion there yet

@mnelson4 mnelson4 changed the title from All authentication methods use "Authentication" header, which is unreliable to All authentication methods use "Authorization" header, which is unreliable May 25, 2016
@rmccue
Member
rmccue commented May 26, 2016

Fundamentally, some server configurations are going to have to change to understand this properly. Using a different header would likely cause authenticated responses to be cached on proxies, which is something we definitely cannot do.

@mnelson4

Thanks for the reply, very good points.

Fundamentally, some server configurations are going to have to change to understand this properly.

Ya that would be ideal. Do you think shared hosting services will be receptive to this change?

Using a different header would likely cause authenticated responses to be cached on proxies, which is something we definitely cannot do.

What about using "Authorization" header, and a custom "X-WP-Authorization-Backup", and maybe set "Cache-control: no-store": we'd primarily using the normal "Authoriaztion" header, but if a server removes that we can use the fallback "X-WP-Authorization-Backup" header which contains the same information, and we instruct proxies to not store this sensitive data (although they probably won't already because of the "Authorization" header, see https://docs.trafficserver.apache.org/en/4.2.x/admin/http-proxy-caching.en.html#client-directives has related info about how one proxy server software decides whether to cache or not.)

@danielbachhuber
Member

@mnelson4 Thanks for starting this conversation. At this point, I don't think we're going to change the current behavior of the API infrastructure. If you identify a problem with a particular server, you could write a bit of custom code that would listen to a custom header instead of the standard Authorization header.

@mnelson4

FYI one of our users was told this by WPEngine regarding usage of the Authorization header:

I’ve checked into the issue, and due to how our platform is configured, authorization via the Authorization header will not be possible. That said, if another header is used, for example ee_authorization, that would be passed back to Apache for processing, and your clients would be able to authenticate with the site. For this, you would need to contact the developer of the plugin to see if they will add an option for specifying a custom header for authentication.

So our user was told using the Authorization header would not be possible and we should code some type of workaround. I don't know if their suggestion is the best, but it does point point to some resistance from hosts to support the Authorization header

@rmccue
Member
rmccue commented Feb 16, 2017

WPEngine needs to change their systems to make this possible, as using a header that isn't the standard Authorization header is not going to work with intermediate proxies.

I'll try and contact someone from WPE.

@wp-michael

@rmccue @mnelson4 I am an engineer at WPEngine. Jason Cohen raised this as a problem to R&D, so we looked into it.

Sure enough, Apache requires a flag(https://httpd.apache.org/docs/current/en/mod/core.html#cgipassauth) to be set to let that through. We aren't setting that, so the PHP variable $_SERVER["HTTP_AUTHORIZATION"] doesn't happen. The data is available in Apache, but the header doesn't make it out.

We found some other work-arounds, but who wants work-arounds when they could just have 'works'.
We're putting in the change for this, so this problem should go away once it gets deployed.

Thanks for contacting us about it!

@rmccue
Member
rmccue commented Feb 17, 2017

@wp-michael Thanks for digging into this one and getting it sorted. :)

@akhanukov
akhanukov commented Feb 17, 2017 edited

Just from an observer's POV as well as a customer of WPEngine's, that was an awesome answer @wp-michael! Wish I would have went to the source the first time around. For others who may host elsewhere and need a workaround, for us to use JWTs to auth to our API, here's our .htaccess workaround:

`# BEGIN WordPress

Header always set Access-Control-Allow-Origin: ""
Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE"
Header always set Access-Control-Allow-Headers "Origin, Authorization, Content-Type"
SetEnvIf Authorization "(.
)" HTTP_AUTHORIZATION=$1
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
`

If anything looks too redundant or ahem, insecure, please let me know. Thanks!

@wp-michael

I am glad we could help.

One more thing we discovered, CGIPassAuth is only available in Apache 2.4.13+
If you are trying to configure an older Apache, it will not like the new directive and will spew errors on start. You will need to use the 'SetEnvIf' approach shown in the post above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment