Protect your PHP websites with CrowdSec
PHP is used by 79% of the websites for which we know the server-side programming language, according to W3Techs’ usage statistics. It is evident that we needed to provide a PHP bouncer to help you secure your websites. This day has finally come.
CrowdSec bouncers can be set up at various levels of your applicative stack: web server, firewall, CDN), etc. And today, we are looking at one more layer: setting up remediation directly at the application level.
Remedying directly in your application can be helpful for various reasons:
- It allows you to provide a business-logic answer to potential security threats
- It gives you a lot of freedom about what and how to do when a security issue arises
While we already published a WordPress bouncer (in the form of a plugin you can install directly from the back office), the PHP library is conceived to be included in “any” PHP application. Let’s pick Drupal as an example.
The bouncer will now help you block attackers and challenge them with CAPTCHAS, letting humans through and blocking bots. Remember that this is only an example, and remediations can be easily extended to fit your own needs!
We will assume that we are running Drupal on a Debian-based machine and Apache as a web server. Those prerequisites are not covered in this tutorial but should apply to other PHP applications.
The first step of this tutorial is to install CrowdSec on our server:
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash sudo apt install crowdsec
Please see the official documentation for complementary information. CrowdSec will detect all the existing services on its own, so you should not have to do any further configuration and get an immediately functional setup!
Testing the initial setup
Now that CrowdSec is installed, let’s launch a web application vulnerability scanner – such as Nikto – and see how it behaves:
./nikto.pl -h http://<ip_or_domain>
We can see that our IP has been detected and triggers various scenarios, the last one being
However, as you might already know, CrowdSec detects, and a bouncer is needed to apply remediation. Here comes the PHP bouncer!
Remedy with the PHP bouncer
Now that we can detect malicious behaviors, we need to block the IP at our website level. As we write these lines, there is no Drupal bouncer available yet. That is why we are going to use the PHP bouncer directly.
How does it work? The PHP bouncer (like any other bouncer) can make an API call to CrowdSec local’s API and check if it should ban incoming IPs, send them a CAPTCHA, or allow them to pass. Since we use Apache as our web server, we can use the install script for Apache.
git clone https://github.com/crowdsecurity/cs-php-bouncer.git cd cs-php-bouncer/ ./install.sh --apache
The bouncer is configured to protect the whole website. However, you can only secure a specific part by adapting the Apache configuration (
Now that our PHP bouncer is installed and configured and that we got banned due to our previous web vulnerability scan actions, we can try to access the website:
The bouncer successfully blocked us! If you were not banned following a previous web vulnerability scan, you could always add a manual decision with
cscli decisions add -i <your_ip>
For the rest of those tests, let’s remove our current decisions:
cscli decisions delete -i <your_ip>
So you blocked the IP trying to mess with your PHP website. It’s nice, but what about IPs trying to scan, crawl, or DDoS it? We all know that those kinds of detection can lead to false positives, so why not return a CAPTCHA challenge to check whether it is an actual user (rather than a bot) instead of blocking the IP?
Detecting crawlers and scanners
We hate crawlers and bad user agents, so we made various scenarios available on our Hub to spot them. Let’s ensure that you have the base-http-scenarios collections from the Hub with
cscli collections list | grep base-http-scenarios:
If it is not the case, you can install it and reload CrowdSec:
sudo cscli collections install crowdsecurity/base-http-scenarios sudo systemctl reload crowdsec
Remedy with a CAPTCHA
Since detecting DDoS, crawlers, or malevolent user agents can lead to false positives, we prefer to return a CAPTCHA for any IP address triggering those scenarios to avoid blocking real users. To achieve this, we will modify the profiles.yaml file.
Add this YAML block at the beginning of your profile:
name: crawler_captcha_remediation filters: - Alert.Remediation == true && Alert.GetScenario() in ["crowdsecurity/http-crawl-non_statics", "crowdsecurity/http-bad-user-agent"] decisions: - type: captcha duration: 4h on_success: break ---
With this profile, a CAPTCHA will be enforced (for 4 hours) to IP addresses that trigger the scenarios
And reload CrowdSec:
sudo systemctl reload crowdsec
Trying out our custom remediations
Relaunching a web vulnerability scanner would trigger many scenarios, and ultimately we would be banned again. So let’s just craft an attack that will trigger the bad-user-agent scenario (the list of known bad user-agents is here). Please note that we need to activate the rule twice to get banned.
And we can, of course, see that we got caught for our actions:
And if we now try to access our website, instead of being simply blocked, we are getting a CAPTCHA.
Once we solve it, we can reaccess the website.
For the next step, let’s unban ourselves again! (
cscli decisions delete -i <your_ip>). Let’s launch our vulnerability scanner:
Unlike the last time, we can now see that we triggered several decisions:
When trying to access the website, the ban decision has the priority:
Now you know how to secure your PHP websites and applications quickly. If you would like to find out more about installing and using the CrowdSec agent, check this how-to guide to help you get started.
About the author
Former pentester, Kevin is now working as DevSecOps at CrowdSec. He is a member of our core team.