A security checklist
He's making a list and checking it twice...
- Haven Gillespie
In the recent partner webinar “Ibexa DXP Cloud Security” (Ibexa partners can log in and view the recording here) I joined William Burke, Director Security of platform.sh, in talking about how we work to secure cloud services like Ibexa Cloud, and self-hosted Ibexa DXP. He presented the risks we face, the consequences of failure, and how a product or process can be secured through careful review of risks and responsibilities. I spoke specifically about securing Ibexa DXP, and included some general advice for web applications.
My talk was based on the Security Checklist in the Ibexa documentation, which I wrote after years of experience with the security concerns facing our partners and customers. I recommend going through this list before launching a project with Ibexa DXP. I would like to discuss important points in the checklist and the webinar here – but please refer to the original list. It contains all the details and will be kept up to date, unlike this blog post.
Roles, your first line of defense
Protect your content with roles, not templates and other tricks. Imagine that anonymous users or external users were able to get into the backend – what would they be able to see and do, given the limitations of their roles? With well-configured roles this would not be a problem. They would only be able to access what they can access anyway in the frontend. The Glare that Obscures explains in more detail the dangers of trying to secure content with template code.
Design your roles carefully. You can arrange user groups in a tree structure and take advantage of the fact that roles assigned to a high-level user group are inherited by lower-level groups. This way you minimize duplication in roles and policies, which makes them easier to audit and maintain. I wrote more about roles in A GDPR-friendly role setup, though my example there is a more complex setup than most will need.
Ensure your roles are complex enough to match your organization well, but no more than that. Minimize the use of the Administrator role. It is safer to make specific, more limited roles for backend use cases like content creation, content approval and publishing, user management, Commerce management, and so forth. Avoid using the Administrator User in production installations, prefer named users placed in the Administrators user group, instead. This helps you with auditing who did what.
Test your roles by logging in as a user in the given user group. Verify that you can access what you should be able to, and can’t access what you shouldn’t. If your user groups and content tree are complex, mistakes in your role design can happen.
The application uses several secrets that must be kept secure: The Symfony APP_SECRET, the Varnish invalidate token, the JWT passphrase, and the Ibexa composer authentication token. Exposure can open several kinds of vulnerabilities, up to and including remote code execution attacks. Make sure you use no default values, keep them longer than 32 characters, replace old ones, and store them securely. That is, not in the project repository on GitHub, not even if the repository is private. The repository is distributed to all your developers’ personal laptops, and production secrets should not be there (except the Ibexa auth token).
Generate secrets using secure random input, e.g.: print bin2hex(random_bytes(32));
Make sure Symfony dev mode is never exposed on the open internet. It contains the output from phpinfo(), which in turn contains environment variables, and they can leak your secrets. I wrote more about secrets in the earlier blog post Can you keep a secret?
Login and user information
Ibexa DXP lets you configure requirements for password length and complexity. Personally, I prefer length over complexity, but adapt it to your needs. Avoid passwords shorter than 10-12 characters and allow more for those who want it. There is no reason to prevent users from entering a 40-character password!
You can also configure password expiration. You may not want to annoy your frontend users with this, but it could be more relevant for backend users. If so, make a separate User content type for them since these settings are tied to the User Account field type.
Ibexa DXP does not provide support for challenge questions, and neither should you. See the earlier blog post Challenge not accepted for the scary reasons why.
You should be careful about what user information you store, especially external users. Under GDPR you are responsible for this information. What you don’t store can’t be leaked in a security breach, so don’t store anything you don’t need, like user pictures or phone numbers.
If you find code making and code breaking interesting, you might enjoy A Very Brief History of Cryptography.
Underlying stack and firewall
Avoid exposing servers on the open internet when not strictly needed. Ensure any servers, services, ports, and virtual hosts that were opened for testing purposes are locked down before going live.
It is possible to lock down Ibexa DXP services that you don’t need, or only need in the backend, using the Symfony firewall. This might include the search engine, GraphQL, and API endpoints. These services are as secure as your roles are, but if you know you don’t need them you can lock them down to reduce your attack surface, and your exposure to any future vulnerabilities.
Staying up to date
If you are an Ibexa partner or customer, please ensure you get security advisory notification emails by selecting “Update notifications” under “Portal access management” in your service portal. If not, check the public security advisory listing.
Use GitHub Dependabot or similar services, both for getting updates for the dependencies you use, and to announce vulnerabilities in packages you provide to others.
I wrote about the security improvements Ibexa gained from using more dependencies in Security Statistics: Safety in Numbers, but we should be aware of the other side of this coin, which is discussed in On cat herding and securing web dependencies.
Have a routine for keeping your users’ access rights up to date. When an employee changes jobs, ensure you disable their user account, no matter how trustworthy they are.
Login monitoring question
In the webinar a question was asked about ways to monitor the logs for excessive repeated attempts to log in, a brute force login attack. When the attempts are made by automated software, and passwords are too short or too simple, the attack can succeed in a short enough time to be useful to the attacker. The simplest way to block excessive requests is of course to use a rate limiter in your web server or proxy, but this may not be quite what you’re after.
If we are making our own log parser for the Apache access log we would look for consecutive failed POST requests (HTTP 4XX status) against user/login, with the same IP address, within a moving time frame. For example, 3 failed requests within 5 minutes. We could build a queue of log entries, one queue per IP address, and discard entries when they expire after 5 minutes. If the queue becomes longer than 3 items, we can raise an alarm. It is possible that advanced solutions like Kibana or Nagios have such a feature built in, that can be worth checking out.
It would be better to track login attempts by username or email rather than IP address, since the attacker may be using a botnet. But these are contained in the POST data of the request, and the access log doesn’t contain POST data by default. The mod_security Apache module can log it. But at this point we may be better off forgetting the log files and instead have a custom user provider track the login attempts. Some SSO providers may have brute force blocking built in, or you could design this into your own user provider. This sounds like an interesting area for further investigation, and perhaps a future blog post!
- Use a CSRF token in forms and rich applications.
- Consider using security headers but adapt them to your site and test them. A good resource: https://securityheaders.com/
- Disable Varnish when using Fastly, to avoid a DOS vulnerability.
- Migration of old sites: Make sure you don’t use md5 password hashes, and not the MySQL 3-byte utf8 charset either. Block execution of scripts in the var directory, see the example vhost.
- Use SSL / https, of course.
- See also our Development guidelines
- OWASP (Open Web Application Security Project) has great resources available for free, including their Top Ten vulnerabilities list and security concepts cheat sheet.
In closing, please keep in mind that security is a continuous process that should affect planning, development, testing, release, maintenance, and new iterations. Everyone on the team should have at least a basic understanding of common vulnerabilities and how to prevent them, and know that security is a team effort. I wish you a merry launch day, and a happy new release!
Please remember our guidelines for safely reporting security issues in Ibexa products and do the same for other vendors. Thanks for reading, and stay secure!