Domino's Server-Side User Security
Sun Nov 01 07:41:55 EST 2015
- Putting Apache in Front of Domino
- Better Living Through Reverse Proxies
- Domino's Server-Side User Security
- A Partially-Successful Venture Into Improving Reverse Proxies With Domino
- PSA: Reverse-Proxy Regression in Domino 12.0.1
The other day, Jesper Kiaer wrote an interesting two-part series of blog posts talking about the security implications of HTTPEnableConnectorHeaders, something I mention in my setup example. In it, he describes the ability to specify an arbitrary username as a security hole, which I don't agree with, but I see where he's coming from. It certainly has, shall we say, implications.
The $WSRU header comes along for the ride when you enable the HTTPEnableConnectorHeaders notes.ini property (off by default) and allows you to specify any user name and have the Domino server trust it completely, as if it had generated it itself. The most straightforward use of this is as a sort of lightweight SSO: if you're already authenticated in to the front-end web server (say, however WebSphere did it when using this), that server can fill in the $WSRU field and have it "count" as a Domino login without forcing the user to log in again. This is sort of what I did to replace my DSAPI filter with a Lua script in nginx.
But what immediately comes to mind is that this allows anyone with HTTP access to the server to type in any ol' username and have Domino accept it. This is why binding Domino's HTTP stack to a local-only (or LAN-only, if you have a nicely-divided server infrastructure) address is important: you wouldn't want a server with this setting facing the public Internet.
The extra good news there is that, when it's fronted by a proxy like nginx, the defaults prevent these $-headers from being passed through from remote clients and all is well, whether or not you specifically account for them.
Now, Jesper also pointed out that, even if you bind HTTP locally, you're still potentially vulnerable to this sort of privilege-escalation problem if you have code running on the server that can make local HTTP calls. And for that case, well... yep. That's true, and it's concerning. However, honestly, that boat already sailed.
Domino's security model has long been lauded by its proponents as thorough and strong, and it is - it's quite good. However, things have gotten a little murkier ever since server-side code has become the primary method of executing Domino apps. Between a Notes client and a Domino server, security is very locked down: the client authenticates via its cryptographic keypair and no lying about its username is going to get the server to treat it as another name (hence why "Run on behalf of" agents don't perform as such when run locally). Running on a server, or between a server and a trusted server ID "client", it becomes a matter of just making up and passing around strings. The permissions used for a given database or view are just whatever the server decided to use as the name when opening it - that's what the hNames parameter of NSFDbOpenExtended is for.
This is how all web user logins work for Domino: the server agrees for itself that, for high-level API calls during that web request, it's going to act like CN=Joe Schmoe/O=SomeOrg
instead of CN=Super Trusted Server/O=SomeOrg
. It's still the server, though, which is why session.getUserName()
in a web-run agent or XPage returns the server name, but session.getEffectiveUserName()
returns the current user or run-on-behalf-of value.
The thing is that the hooks to do this aren't any deeper than the HTTP call with $WSRU set - they're all over the place. The XPages runtime provides a very-convenient hook, but that's not new: the C API is where it all starts, and that's reachable readily from LotusScript and Java. Once you have the same sort of access you'd need to make an HTTP call from an agent, the doors are open pretty wide.
But this isn't even really a problem! To run into any situation like this, you have to have code executing on your server, whether it's inside Domino or not. And if you have that in the hands of a real attacker, then, honestly, this "run on behalf of" business isn't what should keep you up at night. Once you have a trusted developer executing malicious code on your server, you're already done.
Karsten Lehmann - Mon Nov 02 01:33:34 EST 2015
I did some experiments in this area some days ago, when I was writing Java code that calls NSFDbOpenExtended and NIFOpenCollectionWithUserNameList via JNA. I was surprised to see that both methods also work locally in the Notes Client. So I was able to see documents created in a local database that were hidden by reader fields and the names list that NSFBuildNamesList produced for another username was populated with groups from the local names.nsf.
Fredrik Malmborg - Mon Nov 02 01:40:53 EST 2015
That was really straight forward and clear. No further questions your honor.
Jesper Kiaer - Mon Nov 02 03:34:05 EST 2015
I don't think we disagree ..
Jesse Gallagher - Mon Nov 02 09:43:07 EST 2015
Karsten - interesting, and that makes sense. Clients would be willing to lie to themselves as much as they want, but won't get a remote server to trust them so easily.
Jesper - oh, I'm definitely not saying you're wrong. We just disagree on how problematic it is. This is a great topic, too.