One site that I manage that has a lot of complex disease-related data that is given out for free to the public directly via the web site and also via an iOS app.  The entire site is dynamic and derived from multiple back end sources and subsequently causes a bit of a hit to render the information together.  We have often seen other entities (IPs originating from China & Germany recently) decide they want to “scrape” the entire site for all of the content without throttling their connections.  Due to our limited resources (only two front-end application servers), when someone hits us this way, this effectively creates a minor DoS for us.   The best place to try to control for these sort of scenarios would of course be at the load balancer device, but I don’t have control of configuration of them and so I have had to try to take matters into my own hands.

While there are quite a number of ways to cap someone’s impact on your server (mod_bw, mod_ratelimit, IP Tables, etc), most often, these are rendered fairly useless by the client’s IP being replaced by the IP of the LTM (traffic manager / load balancer).

Here’s how I effectively was able to limit other entities ability to hit our site beyond what it could handle.

Step 1:  Install mod_security (and mod_unique if not already loaded) – my mod_security was version 2.7 on CentOS

Step 2: Create a basic config for mod security
########## MOD SEC Basic Config File ###########
LoadModule unique_id_module modules/mod_unique_id.so
LoadModule security2_module modules/mod_security2.so
SecRuleEngine On
SecDataDir /tmp
SecTmpDir /tmp
SecDebugLog /var/log/httpd_logs/modsec_debug.log
SecDebugLogLevel 0
##########################################

Step 3: Add the specific connection limiting configuration anywhere inside the VirtualHost directives of the site you are trying to protect:

####### SPECIFIC rate limiting for this site inside apache VirtualHost #########
<LocationMatch “^/(?!(?:jpe?g|png|bmp|gif|css|js|svg))(.*)”>
#counts everything but images and such
SecAction initcol:ip=%{X-Forwarded-For},pass,nolog,id:4444446
SecAction “phase:5,deprecatevar:ip.mysiteconncounter=1/1,pass,nolog,id:4444447”
SecRule IP:MYSITECONNCOUNTER “@gt 150” “id:4444448,phase:2,pause:300,deny,status:509,setenv:RATELIMITED,skip:1,nolog”
SecAction “id:4444449,phase:2,pass,setvar:ip.mysiteconncounter=+1,nolog”
Header always set Retry-After “15” env=RATELIMITED
</LocationMatch>
ErrorDocument 509 “Rate Limit Exceeded”
############## End rate limit configuration for virtual host here ###########

Step 4: Restart apache!

Some additional notes:
* You can limit what portion of your site is watched in the LocationMatch (instead of the whole site like I did)
* With Mod Security 2.7, I guess you need to add unique rule ID’s to each rule.  For these numbers I chose arbitrarily 4444446 – 4444449
* Change the “@gt 150” to a lower number if you want to lower the threshold for number of connections (each second the number of connections decreases by 1 for each IP) or the speed to which it deprecates the IP connection stat (1/1)
* If you would like to protect multiple sites (additional VirtualHosts on the same server), use a different variable for collecting IPs. In my case above I used “mysiteconncounter” so make sure it is something different, otherwise they will stomp on each other.
* You could probably return a different error code rather than 509 as it is only really partially supported out there.

 

This is how you can perform authentication using RSA Secure ID authentication in your PHP environment. RSA does not provide a module or agent to directly work with PHP, so in order to make it work we will use a PAM PECL extension.  This tutorial assumes you already have a working RSA Manager installation and SecureID tokens, and a running apache/php install.

Step 1:

Install the PAM PECL extension.  You can find it at  http://pecl.php.net/package/PAM

Follow the instructions to install and enable this extension.  This may require some development packages if you’re using the vendor-supplied build of PHP.  So for instance, in the case of RHEL6, this will require assignment of the “RHEL Server Optional” channel.   You can then install the php-devel package.  If using a custom build of PHP, this step should not be necessary.

yum install php-devel
yum install pam-devel
Unzip, and run “phpize” in the directory
Then run “./configure”
Then “make”
Then “make install”

Edit your /etc/php.ini configuration file to include:

[PHP]
extension=pam.so

Step 2:

Install the linux RSA PAM agent following the instructions that are included with that agent.  Download from here: http://www.rsa.com/node.aspx?id=2844

Step 3:

Make sure to run acetest that is provided with the RSA pam authentication agent.  For 64-bit Red Hat, this utility will typically live in /opt/pam/bin/64bit/acetest .  This serves two purposes:  it creates files in /var/ace that we will need to change permissions on, and it also verifies that you are communicating with and properly authenticating against the RSA Manager/server.  If you are not able to verify with the acetest utility, make sure you have properly added the agent to your RSA Manager.

 Step 4:

Change the permissions on files in /var/ace:

Change the group of sdstatus.1 and securid to the web server group (for example, apache)

cd /var/ace
chgrp apache sdstatus.1
chgrp apache securid
chmod 664 sdstatus.1
chmod 440 securid

This is required so that the php process can read the securid file and update sdstatus.1 .  Default permissions only allow root to do this.

Step 5:

Create a PAM configuration file.  The default pam configuration name is “php” unless a different pam.servicename is specified in the php.ini.

As an example, on RHEL 6, you could create this as /etc/pam.d/php with the following entries:

auth         required        pam_securid.so debug
account       required        pam_permit.so

Note: debug is optional, this gives you some potentially useful logging information while you are fine tuning your authentication.  Once you have a working config, debug can certainly be removed.

Step 6:

Create an rsa_auth.php test page to verify if your php/pam/RSA configuration is working:

<html>
<head><title>RSA Test Page!</title></head>
<body>
<?php
$message = “”;
$err = “”;
if (isset($_POST[‘username’] ) && isset($_POST[‘passcode’])) {
if (pam_auth($_POST[‘username’], $_POST[‘passcode’], $err, false) === true) {
$message = “Authentication was Successfull”;
}
else {
$message = “Authentication Failed – $err”;
}
}
?>
<font color=”red”><?php echo $message ?></font><br>
<form method=POST action=”<?php echo $_SERVER[‘PHP_SELF’]?>”>
username: <input type=”text” name=”username” /><br>
passcode: <input type=”password” name=”passcode” />
<input type=”submit” />
</form>
</body>
</html>

Step 7:
Restart apache and try it out!

Please remember to integrate your real PHP authentication page with the appropriate input filtering to better secure and sanitze the input to protect against exploits, etc.