The prior notion while initially secure, leaks over time.
This consideration (and others) leads to the notion of introducing a sort of view into secure storage.
We can change the URL so the object UUID is prefixed by a view UUID:
(The examples use UUIDs. In fact, any big number will serve. SHA hashes are an alternative.)
Where the view UUID is computed when you login, and object UUID(s) are mapped into that space dynamically. Any application-specific access checks need only be computed once - when the object is mapped into the view, and never again. This both simplifies your application, and reduces the load on your server(s).
The number of views would be small (roughly the number of active users), and would expire after some (site and application specific) period of time, or by explicit operator or user action.
This approach also solves another (old) problem with content-management systems - the problem of sharing.
Secure content management systems need to both support and control sharing. If the software does not allow the kind of sharing needed by users site-specific usage, users bypass security (by saving documents/information as unsecured files, and screenshots). This is a problem well-known in content management for decades. At the same time, attempts to allow for and build explicit support for sharing generally fail. Over the years we have seen many complicated schemes that proved hard to implement, hard for users to understand … and still failed to cover all use cases.
Security is about knowing who to trust. We have to assume that (generally) users know who should have a bit of stored information. We also want an audit trail - the ability to see who has accessed an item - to account for information use, and spot any problems. If users resort to bypassing the application, we lose the audit trail. If we allow users to easily share as they see fit, without bypass, then we will have an audit trail.
So sharing must be easy, and at the disgression of the user. Also if sharing covers all use cases, then the application has the opportunity to add value when the shared item is viewed (which in turn could further encourage users to use this form of sharing).
Combining better security with greater application value and higher user satisfaction is a win!
In addition, the above scheme can be implemented very simply and very efficiently, using stock web servers.
Web servers already have very efficient and well-tested support for authentication. Some web servers (nginx is an example) offer extremely scalable and efficient filesystem access. Basic site-wide standard authentication means standard web server logs contain the information needed to construct an audit log. Creating views as directories in the filesystem, placing links to stored files within the view, means security needs to be computed exactly once (when placed in the view), and never again. (In effect, later per-access checks are performed for free by the web server.)
Simpler application software and more efficient access is also a win!
In the super-computing world this approach was once known as “code-hoisting”. In a loop, if an expression always computes the same value, better to compute the expression once outside the loop. In the case described here, the explicit security check is performed exactly once - when the object is linked into the user’s view - and not needed when the object is accessed.
I have worked on a number of content management systems over the years, and from that work had a number of not-well-solved problems in the back of my mind. The end result of the above is better security (in practical use), more efficient execution, and less application logic - pretty much addressing all the unsolved problems - and is both simple and extremely efficient. Pretty much a win-win-win-win. :)