How to secure a CQ5 instance
October 5th, 2011
I am not a security expert. When I was a kid I enjoyed breaking things. When I was a teenage wannabe-programmer, I enjoyed breaking software (mostly games). But I never got a hang on the real hacking, finding security loopholes, stack overflows and such. So I joined Cognifide, learned how to develop in Communiqué, then CQ5 / ADEP (the new CQ5) and became a well-behaved programmer. Up until now.
I’ve done a few trainings recently — either as an internal Cognifide trainer, or as an Adobe consultant. As a part of such training, I normally demonstrate how to secure a CQ5 instance and what happens if you don’t do it properly. The sad thing is — for each training I could Google for Geometrixx to find some live CQ5 site so that I can demonstrate a few common mistakes. And each time I find a new one on the first page of the results. It makes my want to cry to see how one can spend a small fortune on a licence for a powerful platform, and then save on security. Especially that it’s no brain science, and Adobe documented it quite a while ago in the security checklist.
Below you will find a list of those common faults. From requests that shouldn’t make it to the publish instance, dangerous default configurations and, finally, denial of service holes.
home.json, home.xml
Number one and an absolute no-brainer for anyone who knows Sling.
How does it work?
Sling has a default handler for those requests — it will render content of a node. For .xml — whole page, for .json — just the requested node. Additionally, .json supports selectors that will allow infinite recursion, which may result in the instance rendering the entire content tree.
Why is it bad?
- By default
/.infinity.jsonrenders recursively with a maximum depth of 200 nodes; that can overload a server, especially when looped (severity: critical). /.infinity.jsonwill also fill your cache quickly, especially when combined with cache walk-arounds (severity: critical)./.infinity.jsoncan dump the entire repository, including areas that may have some passwords saved — like replication agents (severity: critical).- Recursive calls may expose nodes that were not meant to be read (severity: major).
- It’s exposing your implementation (severity: minor).
How to fix it?
Filter those requests on a dispatcher. If you require .json, make sure it’s available only where it’s necessary. If it’s you generating those files, add a custom selector to the request. This way, you will be able to separate your requests from the default handler and filter the latter on a dispatcher.
access to consoles
There are three consoles that come out of the box:
/admin— CQSE (servlet engine)/system/console— Felix Web Console (OSGi)/crx— CRX console
They are never needed for the end-user, thus they must not be available externally. Even if they are secured with a password.
Why is it bad?
- It’s a quick way of doing a brute-force attack on your admin password. (severity: major)
- If someone gets access to CQSE console, you risk your site being switched-off, or even removed; also, additional applications may be installed on the server, and that’s asking for trouble (severity: critical).
- If someone gets access to Felix console you risk third party bundles being installed, or foundation bundles being replaced with modified, malicious version — an attack virtually impossible to detect (severity: critical).
- Exposing CRX console, in default setup, gives everyone read-only access to whole content, repository configuration (your license key, available disk space, JVM version, etc) (severity: critical).
How to fix it?
Again — Dispatcher is your friend. Filter out those requests. And whenever you need those consoles use either direct port access via VPN, or a separate secure domain (e.g. with HTTP authentication, or hidden behind SSO).
wcm on publish
Did you know a publish instance has a fully functional authoring interface? All you need to get there is:
- login at
/libs/cq/core/content/login.htmland then - hit
/libs/cq/core/content/welcome.html
Also /etc/packages.html is available, and you can download them without logging in. Extremely handy if you have a user in the system, still dangerous even if you don’t. Severity: major.
How to fix it?
Dispatcher filters — deny requests to /libs.
anonymous user access
That’s the main cause, why you must filter the above requests. On publish instance, the default configuration gives anonymous user read only access to the whole repository. And that’s including:
/etc/packageswhere your installed packages are,/etc/replicationwhere one can find DESed transport user’s password (usually it’s for admin)/appswhere your application is exposed and further holes can be found.
(severity: major).
How to fix it?
Carefully trim ACL for anonymous user. Geometrixx home page renders properly with access to:
/content,/etc/clientlibs,/etc/designs,/etc/segmentation.
Each application will require different set, so do it carefully not to strip something you actually need.
That’s about time you asked: I already set my filters — isn’t this step redundant? The answer is: yes, if your filters are perfect and there are no holes in your application, there should be no need to change anonymous user’s permissions. Tight filters are the primary way of securing an instance and ACL cannot replace it. Said that, safe ACL will supplement your filters and should be applied whenever possible. (severity: major).
default passwords
You would be surprised how many sites go with default passwords on publish instance. I don’t think I have to explain why it’s bad.To change passwords, follow the guide here. (severity: critical).
geometrixx on publish instance
Another common mistake is leaving the Geometrixx site on your publish instance. While this will not give anyone access to your system, this site can be indexed by search engine as you can see here and here. And this is bad because it exposes your site before people like me. (severity: major).
How to fix it?
Remove Geometrixx as documented on dev.day.com. You can also create an empty package with areas mentioned there in the filter — installing such package will wipe this content.
denial of service
In the last part I want to review possible options of a Denial of Service attack on a CQ5 instance. First attack can be done by just looping /.infinity.json with a get parameter (to skip a cache). We already secured this one, but it’s still worth mentioning as the weakest spot.
Secondly, for many sites it is possible to have 100% cache coverage. If that’s the case — perfect, once cache is filled, publish instances won’t get any requests and DoS is much harder to perform. If not — stress test the areas that the instance will render to find how much it can handle. You can then use Apache to limit number of requests that make it to the publish instance. It will result in a denial of service when the load exceeds the limit, but your publish will not die / corrupt in the result. And of course — optimise the code that gets most of the load.
Third type of attack will target instance by the use of randomly generated GET parameters, selectors, extensions and suffixes. By making each request unique, the attacker will bypass cache. Quick fix is to accept only the selectors and extensions you actually use, return 301 or 404 status for the rest. Can be applied via dispatcher or directly on the instance. You can also change GET parameters to suffixes, so that results are cached, but be very careful here. There is no way to prevent unique suffixes hitting publish instance, plus it’s an easy way to saturate your cache (dispatcher runs out of disk space). Obviously, if you don’t need GET parameters, or suffixes — filter them out before they make it to the dispatcher, or return 301 / 404 status codes for those requests to avoid caching.
summary
As said, it’s not rocket surgery to secure your instance. Once you set your filters right, you’re pretty safe. Securing for DoS may seem a bit more complicated, but in the end it can be a few foundation classes reused across other projects. So don’t push your luck too long — go forth and secure your instances!




