Cookie Auth on Reverse Proyx
Whenever we run a private server somewhere on the Internet, we need access control. Basic or digest auth was the way to go in the old days, but most of us use some form of cookie based authentication nowadays. That’s fairly easy with server side scripts, but what about static pages or reverse proxies? How can we make the apache server to provide cookie auth?
I want to access my home IoT environment from remote. I also want to view my camera streams when I am on the road. Years ago I punched holes through the firewall to be able to “talk” to my cameras directly. Port knocking provided the access control. That worked well for many years. But for my new system, I wanted a more streamlined, web-app environment to watch the camera feeds.
I used an apache reverse proxy to pull all the camera streams into the web environment. With that, all I need is one port forwarding (port 443) to the web server. I whipped up some scripts to tie everything together and I was almost done.
But how to do access control? The streams were configured as:
<Location /secure/cam1/>
ProxyPass http://127.0.0.1:8081/
ProxyPassReverse http://127.0.0.1:8081
</Location>
so if the link “/secure/cam1” would be known, anybody could access the camera. Obfuscation in not security, so I tried:
<Location />
AuthType Digest
AuthName "kjjahdda@address.com”
AuthDigestProvider file
AuthUserFile "/etc/apache2/secure.pw"
Require valid-user
</Location>
and activated the browser based “popup” window type authentication. That worked nicely, but it interfered with the web-site to webapp conversion, the browser “forgot” the password from time to time and it was not really the streamlined experience I was aiming for. So I wanted to go with the “cookie” way. Create a cookie after successful login and use the cookie to check if access is allowed. But how to protect those reverse proxy links?
It was easier than I expected. Apache’s Rewrite engine is able to look at cookies in the RewriteCond . Something like
RewriteEngine on
RewriteCond %{HTTP:Cookie} !key=([a-zA-Z0-9]+)
checks for a specific cookie that assigns a value to “key” . If it doesn’t find it, the request can be re-routed to a different (e.g. login) page or canceled altogether. But that’s just half the rent. You also want to verify that the value assigned to “key” is correct. That’s a bit more difficult.
RewriteCond %{HTTP:Cookie} key=([a-zA-Z0-9]+)
actually allows you to get the value of the cookie in %1. So, if you assigned the value “password” to “key” in your cookie, you now have “password” in an apache variable to play with. But – how can I verify it?
I went the lazy way. Whenever somebody (most likely .. me) logs in, I create a hash for the key value and set the cookie. I also create a file somewhere in the file system that can easily be verified by the apache web server. So I can do
RewriteCond /tmp/cookies/%1 !-f
to verify that the file exists and re-route the request if it does not.
<location /secure/> # Get the value from a cookie RewriteCond %{HTTP:Cookie} key=([a-zA-Z0-9]+) # Check if a file named the value exists RewriteCond /tmp/cookies/%1 !-f # Re-Route the request to the login page if no match RewriteRule "^/var/www/html/env/home/secure/" "/index.html" [L,R] </location>
It might be a good idea to run a periodical clean up job to remove old “cookie” files.
Depending on what you want, there’s only one more thing to take care of. Since requests without valid cookie will be re-routed to the “index.html” page, you don’t want to put your JavaScript into the “secure” path. Because if not logged in, all JavaScript requests will actually get the “index.html” page instead of the script. Those wrong pages might even get cached and will of course screw up your web-page or web-app.