Skip to content


A funny htaccess file

Sometimes I use Duckduckgo to look up some IP that I caught in my Apache logs doing weird things. Not to do anything out of the information, more out of curiosity indeed. During one of those searches, I stumbled upon what seems to be an accidentally exposed htaccess file (precisely, not .htaccess – the starting dot was missing), and I thought it had some funny contents. Basically, it blocks the IPs of a number of French institutions (although most of the blocks are actually commented out).

I guess it can always happen to be useful to have a little listing of a few institutional IPs, so here are that htaccess file’s contents (I just removed a bunch of redirects as well as the custom 404 document):

# MEEDAT suite infos MEEDAT sce info
deny from 212.23.175.160/27
deny from 212.23.175.64/26
deny from 87.255.128.128/27
# MEEDAT initial
deny from 212.23.175.185
deny from 212.23.175.186
deny from 212.23.175.187
deny from 212.23.175.189
deny from 212.23.175.190
deny from 212.23.175.67
deny from 212.23.175.65
# interieur deny from 212.234.218.196
# mairie marseille deny from 194.242.44.29
#  IANA-BLK deny from 41.248.254.13
# FR-DGCP-BERCY deny from 83.206.120.8
# OLEANE Backbone deny from 194.2.20.67
# JMSP-HOSTING-1 deny from 212.23.178.54
# POOLBB2 deny from 84.55.185.26
# FR-RENATER-193-48-193-52 deny from 193.48.79.7
# AFRINIC-NET-TRANSFERRED-20050223 deny from 81.192.73.99
# Assistance Publique - Hopiteaux de Paris
deny from 164.2.255.244
# FR-MAIRIE-PARIS deny from 194.153.110.6
# AFRINIC-NET-TRANSFERRED-20050223 deny from 81.192.48.34
# FR-VINCI-CONSTRUCTION-FRANCE deny from 217.109.9.225
# COMMUNAUTE-URBAINE-DE-BORDEAUX
deny from 86.65.192.24
# COTEBA-DEVELOPPEMENT-ANTONY deny from 212.99.23.62
#  FR-TUNZINI deny from 217.108.222.57
# Office National des Forets deny from 91.207.176.110
#  Jetmultimedia France deny from 212.23.162.39
# FR-OFFICE-PUB-AMENAGEMENT-CONSTR deny from 90.80.34.250
# CONSEIL REGIONAL D AQUITAINE deny from 81.255.96.222
# FR-NCNUMERICABLE-20050726 deny from 87.231.195.238
# FR-THALES-SA deny from 192.54.144.229
# CEGETEL ACCES INTERNET SECURISE AIS-V2, firewalls deny from 217.19.202.32
# Atos Worldline IPv4 Subnet deny from 160.92.130.65
# SPEIG=Mail de COLAS le 170909 leve deny from 195.25.48.253
#  Jetmultimedia France
deny from 212.23.162.38
# CONSEIL-REGIONAL-IDF
deny from 212.99.12.201
# BOUYGUES deny from 193.57.110.171
# IANA-BLK deny from 41.188.13.2
# FR-CG-ALPES-MARITIMES deny from 193.48.79.7
# IANA-BLK deny from 66.249.72.179
# AFRINIC-NET-TRANSFERRED-20050223 deny from 81.192.73.99
# FR-VINCI-CONSTRUCTION-FRANCE deny from 217.109.9.225
# FR-MAIRIE-PARIS deny from 194.153.110.6
#  N9UF-INFRA deny from 217.19.195.242
# FR-NCNUMERICABLE-20050726 deny from 87.231.195.238
# FR-FRANCE-TELECOM-GLOBAL-HOSTING deny from 195.6.68.62
##### UNILOG en dessous
deny from 212.234.38.188
##### AP HP
deny from 164.2.255.244
##### birco-de
deny from 217.160.82.171
deny from 217.160.83.171

Posted in funnies, Totally pointless, web filtering.


Wow. There IS ad blocking in MSIE. And it works good.

I sometimes have to use MSIE for badly programmed sites that refuse to work with any other browser. And then 2 things bother me:
1) it’s not quite as fast as the other browsers, particularly when I try to quickly browse through the history (like clicking backwards several times, it seems that MSIE wants the page to finish loading before accepting a request to move on to another page)
2) there are ads everywhere

Well, on that second point, I eventually decided to try and find a solution… and I did find it. Microsoft themselves provide us with a page to subscribe to some blocking lists: one by Abine, EasyList (one of the main lists behind AdBlock Plus), and one by PrivacyChoice. You can get them there: http://ie.microsoft.com/testdrive/Browser/TrackingProtectionLists/Default.html.
Once installed, you can manage them in Settings → Safety → Tracking protection.

Posted in Internet, Microsoft.


Life expectancy vs health care expenditures

A few days ago I stumbled upon a funny graph (there) plotting life expectancy at birth vs health care spending in various OECD countries, which pointed out how much the USA were off the chart, with about $8000 health care spending per capita per year and a life expectancy around 78 years, while for instance Denmark achieves a slightly longer life expectancy with less than $5000 health care spending per capita per year (which is still a below average ratio). Note that the currency conversion is done using purchasing power parity.

Digging a bit into this I eventually found the data source, OECD Health Data 2011 – Frequently Requested Data, and even some R source code to plot the thing.

So I loaded the latest data, which as of today are more or less complete up to year 2009 (too many missing data for year 2010 and 2011 yet), adapted the script a bit, and here’s an up-to-date plot:
Life expectancy at birth vs Health care spending per capita in USD PPP
The circles’ diameters are proportional to physician density. Note that Japan is missing (in the graph I mention at the beginning of this post, Japan is featured as a positive outlier, but its data are missing for year 2009), as well as a few other countries due to missing data. I also removed some more because of overlapping points.

And here’s the source (note that you’ll need to move the data from the Excel file a bit into a properly crafted CSV file):

library('penalized');

OECDdata=read.csv("OECD2011-11.csv");

countries=as.character(OECDdata[,1]);
N=length(countries);
expenseGDPperc=OECDdata[,2];
expenseUSDPPP=OECDdata[,3];
lifeExpTot=OECDdata[,4];
physicianDensity=OECDdata[,5];
physicianDensity[is.na(physicianDensity)]=OECDdata[is.na(physicianDensity),6]; # si NA, on prend les données 2008
physicianDensity[is.na(physicianDensity)]=OECDdata[is.na(physicianDensity),7]; # si tjs NA, on prend les données 2007

color=rep("#000000",N);
color[countries %in% c("United States")]="red";
circlebg=rep("#eeeeee",N);
circlefg=rep("#cccccc",N);

remove = rep(FALSE,N);
remove = countries %in% c ("Netherlands", "Belgium", "Germany","Ireland", "Iceland", "Greece", "Italy", "Sweden", "Finland");
remove = countries %in% c ("Netherlands", "Ireland", "Austria", "Iceland");

countries[countries=="United States"]="USA";
countries[countries=="United Kingdom"]="UK";

plot(expenseUSDPPP, lifeExpTot, xlim=c(0,1.05*max(expenseUSDPPP,na.rm=TRUE)), xaxs="i",type="n",
     xlab="Health care spending (PPP US$)", ylab="Life expectancy (years)");
symbols (expenseUSDPPP[!remove], lifeExpTot[!remove], circles=sqrt(physicianDensity[!remove]),
         inches=.8, add=TRUE, fg=circlefg[!remove], bg=circlebg[!remove]);
text (expenseUSDPPP[!remove], lifeExpTot[!remove], countries[!remove], col=color[!remove]);

cor.test(expenseUSDPPP,lifeExpTot,na.rm=TRUE);
lifeExpTot2=lifeExpTot[-which(is.na(expenseUSDPPP)|is.na(lifeExpTot)|countries=="USA")];
expenseUSDPPPb=expenseUSDPPP[-which(is.na(expenseUSDPPP)|is.na(lifeExpTot)|countries=="USA")];
expenseUSDPPPb2=expenseUSDPPPb^2;
expenseUSDPPPb05=expenseUSDPPPb^0.3;
regProba=penalized(response=lifeExpTot2,penalized=~ expenseUSDPPPb + expenseUSDPPPb05,lambda1=1,lambda2=1);
plotLineX=seq(0,1.05*max(expenseUSDPPP,na.rm=TRUE),length=100);
lines(x=plotLineX,y=regProba@unpenalized[1]+regProba@penalized[1]*plotLineX+regProba@penalized[2]*plotLineX^0.3,lwd=2);

Posted in health & medicine, R (R-project).


Firefox 12 available already

Not sure if it’s still a glorified RC or beta build or if this is the final thing (the official release date is tomorrow, April 24), but Firefox 12 seems to be downloadable already by following this link: https://www.mozilla.org/en-US/products/download.html?product=firefox-12.0&os=win&lang=en-US (this is basically the same link as for version 11, except that I edited it to point to 12). I just installed it and it works fine, and shows as 12.0 in the “about” dialog box. Enjoy :)

Posted in Firefox.


Internal server error (500) when setting up htaccess password protection

“500 – Internal Server Error” is one of those annoying error messages that are so useless at finding out what’s wrong. I’d been following this guide to quickly password-protect a site section using Apache and .htaccess directives (you know, “Require valid-user” and such), and then came this error.
My .htaccess file looked like this:

AuthUserFile /home/somepath/.htpasword
AuthType Basic
AuthName “Private area”
Require valid-user

After commenting out each line one by one, it seemed at first that the error appeared on “Require valid-user”. But as pointed out in this post, just because the error appears when you add this line doesn’t mean it’s the culprit. And in my case, the problem was actually on the first line: there was a typo in the password file name. That’s really tricky because despite the typo, the site did ask me for user and password (so it seemed as if this was working properly)…
So, when you get that error and manage to figure out which lines triggers it, do analyze all the lines that work together with the triggering line!

Posted in web development.


How to get instantly banned from Twitter

Although Twitter try to give themselves an image of not being too prompt at fulfilling subpoenas, they appear to be die-hard anonymity haters. Proof, you ask? Well, I ran a little experiment today: I signed up an account from Tor and with a trashable e-mail.
I then started to complete the signup tutorial (you know, that silly welcome process where they almost force you to follow people who already have lots of followers). At some point, I reached for the confirmation e-mail and clicked it.
The confirmation seemed successful at first. Then when I tried to reach the next step, I got a message saying I should confirm my e-mail (with a non-working option to resend the confirmation e-mail). After refreshing the page, oops, my account was suspended already. Not a single tweet, barely any follow (and I only followed suggestions from the very guided welcome guide)… just suspended:
Twitter account suspended with 0 tweets and only 5 followees

Looks like I can trash that account already. Only problem is: not sure if I got banned because of the trashable e-mail or because of the Tor IP.
Nevermind, on with the experiment, I created a non-trashable e-mail (well, a “not as trashable” one, at least), and used it to sign up again. Luckily, Tor kept me on the same IP so I was able to check how it goes when signing up from a banned IP: Twitter doesn’t tell you there’s a big fat red flag on your IP, but it does give you a ReCAPTCHA (*sigh*), asking if you’re human.
On with the sign up, completed the tutorial, then comes the e-mail validation and… all good, apparently.

So, the ban seems to have been triggered by the trashable e-mail. Or maybe a combination of Tor + the trashable e-mail. That’s a bit stupid though, because:
1) as long as I’m on Tor I can just create a new e-mail account and then throw it away. It’s a bit more time-consuming than a real trashable e-mail, but just as anonymous.
2) they could just tell the user at account creation that the e-mail address they try to use is forbidden, instead of being an ass.

When I get the occasion, I’ll try to create an account from a “clean” IP (not Tor, not hosting company), and see how it goes…

Posted in privacy, social network stuff.


A quick iptables mini-guide

I’ve always had trouble dealing with iptables. So instead of trying to do some extensive configuration, I figured I’d start small by temporarily configuring a few things and wrapping them up in a post here.

Before going further, a small note about IPv6: iptables only deals with IPv4 traffic. For IPv6, you’ll have to use ip6tables. I didn’t really look at it much for the moment, but the commands seems pretty similar.

First, the command to list all rules:
iptables -n -L
NB: the -n is an extra option to avoid doing reverse DNS lookups (they can take a while, so you may want to avoid them when you have more than a few rules).

If you want, for instance, to list only the input rules, then it’s like:
iptables -n -L INPUT

For a more verbose output (notably, with packets and bytes count):
iptables -nv -L INPUT

Now before you start messing around, you may want to backup your current configuration:
iptables-save > myIptablesBackup.txt
To restore it later:
iptables-restore < myIptablesBackup.txt
NB: restoring a backup will first flush the configuration, then apply the backup. If you want to avoid the flush, specify -n (aka --noflush). But if you don't flush when restoring, the restored configuration will be added to the current one, even if this results in duplicates.

To block all traffic from a specific IP:
iptables -A INPUT -s 91.121.23.114 -j DROP
(NB: this example IP is one currently really performing server scans, notably looking for poorly secured phpMyAdmin installation)

To block all traffic from an IP range:
iptables -A INPUT -s 91.121.23.0/24 -j DROP
(NB: this one, although inspired from the above-mentioned IP, is NOT a real problematic IP range)

Now, to be a bit more subtle, you may want to block only a specific protocol and port. For this you use respectively the parameters -p and --dport. For instance, to block TCP on port 80:
iptables -A INPUT -s 91.121.23.114 p tcp --dport 80 -j DROP
It is to be noted that --dport doesn’t seem to work when specified without a port. My limited knowledge in networking doesn’t allow me to understand the rationale behind this, I suppose some protocols don’t use ports?

To delete a specific rule, for instance the third input rule:
iptables -D INPUT 3

To delete all input rules (NB: if you use fail2ban, you’ll notice that fail2ban adds an entry to the INPUT chain. I’m not sure of what it does, but I don’t think it’s a good idea to remove it… so just make sure you backed up your configuration first):
iptables -F INPUT

To delete all rules (NB: same remark as above):
iptables -F

A more restrictive configuration could be to deny all traffic but some specific one. Note that this has to be carefully planned, so that:

  • you don’t lock yourself out (hint: beware if you have a dynamic IP… the best idea IMO is to let your SSH port open to all – although you may want to move it to something else than port 22 – and then use fail2ban to protect it)
  • you don’t lock your legit visitors / customers out (usually that’s the part you don’t forget. Not too hard too, usually you just need to let them go to port 80)
  • you don’t break normal interactions between your servers (like, your Apache server connecting to your SQL server, or your main server connecting to your backup server)
  • you don’t kick your server monitoring tools, or your hosting company’s server monitoring tools (usually they have some, to detect when your server is down so they send a tech to reboot/fix it)
  • you don’t lock out your disaster recovery tools (virtual KVM and such)

Once you’ve carefully thought about what needs to be allowed, the syntax to explicitly allow traffic is just the same as the syntax to drop, except that you replace “DROP” with “ACCEPT”. For instance:
-A INPUT -p tcp --dport 22 --source [your IP] -j ACCEPT
And then when you’ve put all your ACCEPT rules, finish with a:
-A INPUT -i eth0 -j REJECT or
-A INPUT -i eth0 -j DROP
NB: it might be a good idea to remain interface-specific (thus the -i eth0), I’m not too sure what happens if you block the local loopback. To find out your interface names, just use ifconfig.
My second source (unfortunately in French) contains a complete example configuration, but remember that some settings are “hosting company-specific”.

Sources:

Bonus: blocking some spammers from my postfix relay

Not sure if this is the most appropriate way to deal with those, but that’s pretty efficient ;)
iptables -A INPUT -s 180.241.244.156 -j DROP
iptables -A INPUT -s 46.134.253.175 -j DROP
iptables -A INPUT -s 91.185.252.14 -j DROP
iptables -A INPUT -s 72.55.148.21 -j DROP
iptables -A INPUT -s 93.48.97.149 -j DROP
iptables -A INPUT -s 176.9.35.83 -j DROP
iptables -A INPUT -s 64.26.174.67 -j DROP
iptables -A INPUT -s 108.170.42.155 -j DROP
iptables -A INPUT -s 95.9.249.219 -j DROP
iptables -A INPUT -s 186.61.2.80 -j DROP
iptables -A INPUT -s 95.232.147.85 -j DROP
iptables -A INPUT -s 200.62.249.86 -j DROP

Posted in Linux, security, servers.


Linux: command aliases are the s*** :)

Since I’m getting seriously fed up with the way Ubuntu messes with the UI, I recently gave a try at Debian. One of the first thing the struck me was the unavailability of the ‘ll’ “command”. After digging a bit, I found that this is technically not a command but just an alias. And aliases can be created quite easily. For instance for ll, you’d just need to type the command:
alias ll='ls -l'

To make the alias permanent, you should add it to your ~/.bashrc file. Depending on the distribution and on the user, this file may also contain other interesting stuff. I ended up uncommenting the whole following block, so as to have the ll and l aliases, as well as colorized file names:
# You may uncomment the following lines if you want `ls' to be colorized:
export LS_OPTIONS='--color=auto'
eval "`dircolors`"
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -l'
alias l='ls $LS_OPTIONS -lA'

You can also add some time-saving commands. For instance, I find it a hassle to often type apt-get update and apt-get upgrade so I added this:
alias au='apt-get update && apt-get upgrade'
Now no excuse not to upgrade often ;)

NB: if you want to configure aliases for all users at once, you can set them in /etc/profile instead of each individual .bashrc file.

Source (with a nice other idea to save more typing with alias): Terzza – Linux “ll” command / alias

Posted in Linux.


How to check with PHP if the page is being served over HTTPS

As a follow-up to this guide on how to get an SSL certificate and configure Apache to use it, it seems logical to look for a way to detect, server-side, whether or not a specific visitor is connecting over HTTPS.

Fortunately, PHP has a trivial way to check this: the $_SERVER['HTTPS'] variable. It will be set to ‘on’ whenever the page is loaded over SSL. This way you could for instance force all visitors to use SSL, like this:
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') {
$url = 'https://'. $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
header('Location: '.$url);
exit;
}

Note that the isset() part is to avoid throwing an error when the page isn’t served in SSL: on most server, in this case, the $_SERVER['HTTPS'] variable won’t be set at all.*
The exit is important too, because otherwise the page execution will continue, so for instance if the user submitted GET data, then you’ll submit the data twice if you don’t stop the execution with the exit.

Sources (note: those sources have alternate solutions for when the above solution doesn’t work, e.g. when using PHP over fastCGI in nginx):

Posted in cryptography, web development.


How to create and install an Apache SSL certificate (either self-signed or not)

This is actually, once again, simpler than it looks from the length of most tutorials that can be found elsewhere. So I’ll just list the steps and the key commands, and I’ll let you figure out how to move the files around.

Generate private key:
openssl genrsa -des3 -out servPriv.key 4096

Generate CSR (Certificate Signing Request):
openssl req -new -key servPriv.key -out servRequest.csr

Remove Passphrase from Key
cp servPriv.key servPriv.key-passwd
openssl rsa -in servPriv.key-passwd -out servPriv.key

NB: this is to prevent Apache from asking for the key password every time it starts, but obviously this means your key is no longer protected! To protect it a bit more, you should chown it to root, and chmod it 400 (ie, can only be read by root). For some reason Apache should still be able to read it.

Send your signing request to your certificate provider. Or self-sign your certificate:
openssl x509 -req -days 365 -in servRequest.csr -signkey servPriv.key -out signedStartSSL.crt

In Apache, enable mod_ssl. It can be done in a few clicks via Webmin, or just add this somewhere in your Apache configuration files:
LoadModule ssl_module modules/mod_ssl.so

And finally, add something like this somewhere in your Apache HTTPd configuration (note that SSLCertificateChainFile and SSLCACertificateFile are provided by the certificate signing authority thus don’t apply if you self-signed your certificate):

<VirtualHost *:443>
   DocumentRoot /var/www
   SSLEngine on
   SSLProtocol all -SSLv2
   SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM

   SSLCertificateFile /home/certifs/signedStartSSL.crt
   SSLCertificateKeyFile /home/certifs/servPriv.key
   SSLCertificateChainFile /home/certifs/sub.class1.server.ca.pem
   SSLCACertificateFile /home/certifs/ca.pem
   SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
</VirtualHost>

Restart Apache and test :)

Sources:

Posted in cryptography, Linux, security, servers.