Outils pour utilisateurs

Outils du site


issue101:site_web_avec_infrastructure

Ceci est une ancienne révision du document !


Now that that our Linux VM is built, we must add security for better server protection; this will be accomplished by using the Linux firewall capabilities. Afterwards, we will install a web server and set up additional security on the web server.

Today we will focus on the Linux firewall. We will use iptables, standard Linux firewall functionality.

A Firewall is basically a set of rules. As best practice, we'll use the “deny access” default rule – this means that unless specified otherwise, an incoming network packet will be dropped.

External access to our server will be allowed under: • SSH - for remote control • HTTP -server web pages (our website)

Right now, anybody can try connecting to our server via SSH. Obviously, that will not be possible without the private key; however, we'd like to limit who can even try to connect to our server – this is just best practice and limits access to any additional potential hacks.

For example – let's suppose you live in the US – it's probably a good idea to allow SSH connections only from the US (any SSH connection attempt from outside the US is not legitimate – it's not you!!! - so it should be banished).

In addition, we may decide we will not do business with specific countries – we will block any web access (HTTP) from these countries. In my example, I will choose Canada (note here – this is only an example, there is absolutely nothing wrong with Canada what.so.ever – I am just choosing a country which is a Democracy, this way, I know I won't get into trouble!!!).

Please note that checking the incoming country is not foolproof – the source connection can spoof the IP address (or just VPN into a server from an unblocked country). Anyway – this is good protection against automatic bot scanners and will definitely help keep hackers away.

Without getting into too much detail, the firewall rules can be set for incoming, outgoing, and forward connections.

Since we are not forwarding anything, we will just set rules for incoming (most important), outgoing (more later on why) and ignore forwarding (by default forwarding is disabled in the kernel anyway).

Step by step now

Quick reminder: only sudo (or root) can set up firewall rules. To switch to root, I recommend typing:

sudo su

1 – Reset any firewall rule and DROP any incoming connections:

Most distributions come with some type of firewall rules set up by default. (Centos & Suse do for sure – not totally sure about Ubuntu).

We will reset any rules so we can start from scratch:

iptables -F

iptables -X

And by default DROP any incoming connections:

iptables -P INPUT DROP

2 – Allow local connections (to localhost):

iptables -A INPUT -i lo -p all -j ACCEPT

iptables -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

3 – Block incoming connection if it originates from a specific country:

There are several ways to check the country-of-origin of an incoming connection: • iptables geoip • loading country blocks into ipset

iptables with geoip is based on xtables-addons, which is an extension of iptables. This works pretty well. However, it's not really a “standard” - meaning xtables is not delivered with some distributions (requires compile from sources & install). For example, I was unable to make this work with Arch Linux on ARM architecture (not saying it is not working, just saying I was unable to make it work – big difference!).

ipset is a companion application to iptables – it can load in-memory ranges of IP addresses, and iptables can leverage ipset to test if an IP is within this range.

As geo-localization, I will choose ipset – which seems to be available as a packaged install to any distribution I have tried so far.

sudo apt-get install ipset

Let's summarize what we want to achieve here: • Get the IP range block we want to forbid (country based). • Load that range into ipset. • Add an iptable rule which checks if source is within that range (Canada in our example). • If yes, block. • If not: • • Allow if target is HTTP (a web page). • • If target is SSH, we must also check country of origin is USA (same as above – with ipset).

I hope you follow me here!!!

IP blocks by country can be found here: http://www.ipdeny.com/ipblocks/data/aggregated

We'll get the blocks of US and Canada – either download the file or use wget:

wget http://www.ipdeny.com/ipblocks/data/aggregated/ca-aggregated.zone

wget http://www.ipdeny.com/ipblocks/data/aggregated/ca-aggregated.zone

Now load the blocks into ipset's memory: Create an ipset bucket called myset_CANADA: ipset create myset_CANADA hash:net

Load the blocks corresponding to Canada into myset_CANADA:

for i in (cat ca-aggregated.zone); do ipset add myset_CANADA $i; done

Same for US block range:

ipset create myset_US hash:net

for i in (cat us-aggregated.zone); do ipset add myset_USA $i; done

Now we'll block anything coming from Canada (conjunction of iptables & ipset):

iptables -A INPUT -m set –match-set myset_CANADA src -j DROP

If the rule above is hit, the connection is dropped (-j DROP does that) and we exit the firewall.

4 – If we get up to here in the firewall chain

We can accept any HTTP incoming connections:

iptables -A INPUT -p tcp –dport 80 -j ACCEPT

If rule above is hit (meaning “true”), the request is accepted (-j ACCEPT) and we exit the firewall.

5 – If we get to here

The source is not coming from Canada and it’s not an HTTP request. If the request in not SSH, drop the request and exit the firewall:

iptables -A INPUT -p tcp ! –dport 22 -j DROP

6 – If we've got this far

It is a SSH request (and not from Canada). Let's check if the source country is allowed (USA in our example).

Before accepting, let's write into the system log that access to port 22 has been granted. We will log this information into /var/log/messages (default system log file). Logging is important for security reasons – by running statistics on /var/log/messages you will find out who tried to access your system. Note that we do not track who has connected but who tried to connect:

iptables -A INPUT -j LOG –log-prefix “Accepted SSH ” –log-level 7

iptables -A INPUT -m set –match-set myset_USA src -j ACCEPT

Just in case we missed anything, any connection arriving to the command above will be dropped (remember – we drop everything by default unless specified otherwise):

iptables -A INPUT -j DROP

It’s not mandatory – but we can add some additional security to the above rules.

Let's imagine that somebody really wants to hack your system by trying every combination of RSA key possible – that is called a brute-force-attack. No worries – with a 10K RSA key, it is probably not possible (note the word probably – when talking security, you cannot ever be sure!).

There is something we can do about that – if a specific IP tries to connect more than x times (let's make it 5) to our server on port 22, we can temporarily ban that IP address for a few minutes – let's make it 5 (300 seconds). So this means that an attacker can potentially try 5 combinations every 5 minutes. As you probably understand, brute force will not work at this pace!!!

Below, we're telling iptables to keep track of connections to port 22 for 300 seconds. If a (failed) hit count gets to 5, the connection is denied for the next 5 minutes:

iptables -A INPUT -p tcp -m tcp –dport 22 -m state –state NEW -m recent –set –name DEFAULT –rsource

iptables -A INPUT -p tcp -m tcp –dport 22 -m state –state NEW -m recent –update –seconds 300 –hitcount 5 –name DEFAULT –rsource -j DROP

Then, follow these with the same block-rules as before:

iptables -A INPUT -j LOG –log-prefix “Accepted SSH ” –log-level 7

iptables -A INPUT -m set –match-set myset_USA src -j ACCEPT

iptables -A INPUT -j DROP

Careful – this rule also applies to yourself!

More about logging and checking who tried to access the system…

This command will display any SSH connection attempt to your system:

cat /var/log/messages | grep “Accepted SSH”

You will quickly get a hefty output (“quickly” means minutes of server up-time), which will not be easy to read.

This revised version is probably more useful and will give the list of unique IP attempts – sorted by number of connection attempts:

cat /var/log/messages | grep “Accepted SSH” | awk -FSRC= '{print $2}' | awk '{print $1}' | sort | uniq -c | sort -n

A quick explanation of above command: • It outputs the content of the file /var/log/messages. • It keeps only lines where the keywords “Accepted SSH” exist. • It grabs the text following the keyword SRC= (IP address of incoming connection). • It sorts the list. • It gets only the unique IPs, but counts the number of occurrences of each unique IP. • It sorts descending as numbers (sort -n).

The goal of this article is firewall and security. However, I strongly believe that security and scripting go hand-in-hand. Logging intrusion attempts is great but not using the data is useless. As you can see, a quick shell command was able to provide very useful information – extremely quickly. I can now, for example, ban the topmost 10 IPs who tried to log in to my system.

The following command will ban the IP 10.10.10.10 by inserting the rule on top of all rules (-I INPUT 1):

iptables -I INPUT 1 -s 10.10.10.10 -j DROP

Have fun and please make sure not to ban… yourself!

7 – Output rules:

Many times, firewalls will enforce rules only for incoming connections – meaning they’ll allow wide-open output traffic. This is not a good practice – imagine that a hacker gets to your computer and is able to install server software which could then create a tunnel via a random port to the attacker's server and therefore provide full access to the attacker.

We will also close this loophole. Basically we will allow outgoing access to: • SSH (for our remote access), this is TCP port 22. • HTTP and HTTPS (for web pages), these are ports 80 and 443. • DNS (so our requests can be resolved!), this is port 53.

You probably got the point: • By default, DROP any output connections, unless we specifically tell otherwise. • Allow connection to localhost (the server itself). • Allow SSH, DNS, HTTP & HTTPS.

iptables -P OUTPUT DROP

iptables -A OUTPUT -o lo -p all -j ACCEPT

iptables -A OUTPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -p tcp –dport 22 -j ACCEPT

iptables -A OUTPUT -p udp –dport 53 -j ACCEPT

iptables -A OUTPUT -p tcp –dport 53 -j ACCEPT

iptables -A OUTPUT -p tcp –match multiport –dports 80,443 -j ACCEPT

iptables -A OUTPUT -j DROP

Let's put all this together…

First build the block of IP addresses. Run all below as root (or sudo):

apt-get install ipset

wget http://www.ipdeny.com/ipblocks/data/aggregated/ca-aggregated.zone

wget http://www.ipdeny.com/ipblocks/data/aggregated/us-aggregated.zone

Now let's clean all firewall rules:

iptables -X

And make sure all rules were really deleted – you should see this:

Then add the firewall rules in a text file (see box on next page).

In order to test this out, I would recommend the following: • Use wget to get the blocks of IPs, and keep the files. • Copy / paste the code above to a shell file (text file with extension .sh and make it executable with chmod +x [filename]). • Run the file. For my example, I'll call this file /usr/local/sbin/firewall.sh

You should now have the firewall fully loaded and operational.

IMPORTANT – iptables -F resets the firewall and locks your ssh session out!

When you run the file, your terminal will be “locked”. This is because we reset the firewall by blocking all rules by default. Just try connecting again to iceberg from another terminal. If it works – you should be all set, but, if you cannot, stop and restart the VM from the Digital Ocean panel. After the restart, the rules are not loaded, so you can fix that problem: For example, I allowed the US IP blocks because I live in the US, did you load the right blocks of IPs from where you live?

I will now suppose everything worked well – we will then set both scripts to run at startup.

In ubuntu 14.04, edit and add both files to /etc/rc.local (shown below).

Note the sleep 10 – we're telling iceberg to wait 10 seconds before running our scripts – this is to ensure that the network is up & running before we set up the firewall.

I know a few of you may find the sleep 10 not optimal and would rather use upstart's dependencies rules. I personally think it is too much trouble and safe enough (even if somebody connects in those 10 seconds, he'd be locked by the iptables -F) – not to mention that upstart seems to be end-of-life software (even Canonical decided to switch to systemd in newer Ubuntu versions – this doesn't mean I support or not systemd, I am just noting Canonical’s decision).

Anyway, during your next reboot, you should be automatically all set, with a system pretty well protected against intrusions.

If you'd like to confirm the scripts have been properly executed at startup, as root run this:

iptables -L

and you should get the firewall rules displayed on the screen.

Next month, we will install Apache (Web server) and secure Apache.

issue101/site_web_avec_infrastructure.1443477571.txt.gz · Dernière modification : 2015/09/28 23:59 de d52fr