Hi all, i was about to setup a new webserver for some of my private sites that i wanna host, and since i love security i wanted to set it up as secure as possible, and share with you how to setup a secure webserver using SuSE linux 7.3 (since its the distro i use). I hope that it will help you in setting up a secure server.


------------------
The webserver is one of the favourite targets on the internet today. Webservers must be accessible from any location on the internet inorder to allow computers/users to view the websites. One of the most common dangers is defacements of sites, which is mostly done by so called script kiddies or crackers. Defacements can lead to serious company damage as in downtime, and confidence towards its customers and the net in general. Even worse is if the webserver holds sensitive information like credit card details, that on some defacements are published openly on the defaced site.

Each service must be tightend as well as possible for security reasons, meaning that the services should be launched as standalone only and not launched as root. That secures the point that if a service is compromised, the attacker has only as much access as the service is running on (eg for webserver, let user www be the one to start that service instead of root).

To setup the webserver securely, create 7 partitions on the HD.

/
/var
/tmp
/home
/usr
/usr/local
/etc


You then install the MINIMUM installation only (no gui, gpms, inetd, rpc, pico, compilers etc...). Just the minimum OS installation, and add the following packets to it.

compat
sudo
apache
bindutil
SuSEfirewall II
harden_suse
mod_ssl
scanlogd
seccheck
Aide
proftpD
ftpdir
(instead of sendmail, install postfix)
plus anything else you need (e.g. data bases, modules for the Apache)

Before installing any of the above mentioned packages, check to make sure if any updates are available for them, and update them if necessary.


Before starting with the actual work, all "standard" Linux configurations such as entering the name server, configuration of the network interface, setting up users, etc. should be executed. Initially all unnecessary services should be inactivated and authorizations withdrawn from privileged programs not absolutely needed. This can easily be done with the
harden_suse tool.

server# harden_suse

This causes extensive changes to the system, which are all recorded in /etc/harden_suse.log and which can be undone with the /etc/undo_harden_suse script. Users of other Linux distributions like Red Hat can possibly use the Bastille script or something similar, although these represent a slightly different approach.

All services with net access except SSH are deactivated and only the following privileged suid and sgid programs remain:

server# find / -perm -04000 -type f -exec ls -ld {} \;
-rwsr-x--- 1 root trusted 23840 Mar 11 11:26 /bin/ping
-rwsr-x--- 1 root trusted 30750 Mar 11 11:37 /bin/su
-rwsr-x--- 1 root trusted 21268 Mar 11 11:10 /usr/bin/crontab
-rwsr-xr-x 1 man root 85460 Mar 11 11:24 /usr/bin/man
-rwsr-xr-x 1 root root 15308 Mar 11 11:26 /usr/bin/rcp
-rwsr-xr-x 1 root root 11052 Mar 11 11:26 /usr/bin/rlogin
-rwsr-xr-x 1 root root 8104 Mar 11 11:26 /usr/bin/rsh
-rwsr-x--- 1 root shadow 38340 Mar 11 11:50 /usr/bin/gpasswd
-rwsr-x--- 1 root trusted 22184 Mar 11 11:50 /usr/bin/newgrp
-rwsr-xr-x 1 root shadow 27920 Mar 11 11:50 /usr/bin/passwd
-rwsr-x--- 1 root trusted 56600 Mar 11 18:41 /usr/bin/sudo
-rwsr-xr-x 1 root root 20300 Mar 11 11:26 /usr/sbin/traceroute
-rwsr-xr-x 1 root root 6132 Mar 11 09:36 /usr/lib/pt_chown
server# find / -perm -02000 -type f -exec ls -ld {} \;
-rwxr-sr-x 1 root tty 9452 Mar 11 11:26 /usr/bin/write

Next, vi into /etc/rc.config and edit the following:

START_HTTPD="yes"
START_FW2="yes"
START_SCANLOGD="yes"

That makes sure that the webserver, the firewall and the scanlog daemon are started upon system boot.

Now we continue with the configuration of the local firewall and change the following lines in the file /etc/rc.config.d/firewall2.rc.config (a detailed description of the individual variables is included in the file):

(I usually setup my own firewall rules via iptables, but since this is not a firewall tutorial i'll just copy paste my webservers firewall here that comes along with my suse distro I will only paste the options that i have edited or need, depending on my network setup. There are many more options, but i will only paste the ones related to the webserver as a standalone computer (not any lans, DMZ etc....) ) :


# 1.)
# Should the Firewall be started?
#
# This setting is done in /etc/rc.config (START_FW2="yes")

########################################

#
# 2.)
# Which is the interface that points to the internet/untrusted networks?
#
# Enter all the network devices here which are untrusted.
#
# Choice: any number of devices, seperated by a space
# e.g. "eth0", "ippp0 ippp1 eth0:1"
#
FW_DEV_EXT="eth0" #This is what connect with to my router.

########################################

# 8.)
# Do you want to autoprotect all running network services on the firewall?
#
# If set to "yes", all network access to services TCP and UDP on this machine
# will be prevented (except to those which you explicitly allow, see below:
# FW_SERVICES_{EXT,DMZ,INT}_{TCP,UDP})
#
# Choice: "yes" or "no", defaults to "yes"
#
FW_AUTOPROTECT_SERVICES="yes"

########################################

# 9.)
# Which services ON THE FIREWALL should be accessible from either the internet
# (or other untrusted networks), the dmz or internal (trusted networks)?
# (see no.13 & 14 if you want to route traffic through the firewall) XXX
#
# Enter all ports or known portnames below, seperated by a space.
# Common: smtp domain
FW_SERVICES_EXT_TCP="80 443 22 21" #http, https, ssh, 21 for ftp uploads
# Common: domain
FW_SERVICES_EXT_UDP="" # Common: domain


########################################

#
# 11.)
# How is access allowed to high (unpriviliged [above 1023]) ports?
#
# You may either allow everyone from anyport access to your highports ("yes"),
# disallow anyone ("no"), anyone who comes from a defined port (portnumber or
# known portname) [note that this is easy to circumvent!], or just your
# defined nameservers ("DNS").
# Note that if you want to use normal (active) ftp, you have to set the TCP
# option to ftp-data. If you use passive ftp, you don't need that.
# Note that you can't use rpc requests (e.g. rpcinfo, showmount) as root
# from a firewall using this script (well, you can if you include range
# 600:1023 in FW_SERVICES_EXT_UDP ...).
#
# Choice: "yes", "no", "DNS", portnumber or known portname, defaults to "no"
# if not set
#
# Common: "ftp-data", better is "yes" to be sure that everything else works :-(
FW_ALLOW_INCOMING_HIGHPORTS_TCP="yes"
# Common: "DNS" or "domain ntp", better is "yes" to be sure ...
FW_ALLOW_INCOMING_HIGHPORTS_UDP="yes"

#############################################

#
# 12.)
# Are you running some of the services below?
# They need special attention - otherwise they won´t work!
#
# Set services you are running to "yes", all others to "no", defaults to "no"
#
FW_SERVICE_AUTODETECT="yes" # Autodetect the services below when starting
#
# If you are running bind/named set to yes. Remember that you have to open
# port 53 (or "domain") as udp/tcp to allow incoming queries.
# Also FW_ALLOW_INCOMING_HIGHPORTS_UDP needs to be "yes"
FW_SERVICE_DNS="no"
#
# if you use dhclient to get an ip address you have to set this to "yes" !
FW_SERVICE_DHCLIENT="no"
#
# set to "yes" if this server is a DHCP server
FW_SERVICE_DHCPD="no"
#
# set to "yes" if this server is running squid. You still have to open the
# tcp port 3128 to allow remote access to the squid proxy service.
FW_SERVICE_SQUID="no"
#
# set to "yes" if this server is running a samba server. You still have to open
# the tcp port 139 to allow remote access to SAMBA.
FW_SERVICE_SAMBA="no"

###########################################

#
# 16.)
# Which logging level should be enforced?
# You can define to log packets which were accepted or denied.
# You can also the set log level, the critical stuff or everything.
# Note that logging *_ALL is only for debugging purpose ...
#
# Choice: "yes" or "no", FW_LOG_*_CRIT defaults to "yes",
# FW_LOG_*_ALL defaults to "no"
#
FW_LOG_DROP_CRIT="yes"
#
FW_LOG_DROP_ALL="no"
#
FW_LOG_ACCEPT_CRIT="yes"
#
FW_LOG_ACCEPT_ALL="no"
#
# only change/activate this if you know what you are doing!
FW_LOG="--log-level warning --log-tcp-options --log-ip-option --log-prefix SuSE-FW"

####################################################

#
# 17.)
# Do you want to enable additional kernel TCP/IP security features?
# If set to yes, some obscure kernel options are set.
# (icmp_ignore_bogus_error_responses, icmp_echoreply_rate,
# icmp_destunreach_rate, icmp_paramprob_rate, icmp_timeexeed_rate,
# ip_local_port_range, log_martians, mc_forwarding, mc_forwarding,
# rp_filter, routing flush)
# Tip: Set this to "no" until you have verified that you have got a
# configuration which works for you. Then set this to "yes" and keep it
# if everything still works. (It should!) ;-)
#
# Choice: "yes" or "no", defaults to "yes"
#
FW_KERNEL_SECURITY="yes"

#####################################################

#
# 19.)
# Allow (or don't) ICMP echo pings on either the firewall or the dmz from
# the internet? The internet option is for allowing the DMZ and the internal
# network to ping the internet.
# REQUIRES: FW_ROUTE for FW_ALLOW_PING_DMZ and FW_ALLOW_PING_INTERNET
#
# Choice: "yes" or "no", defaults to "no" if not set
#
FW_ALLOW_PING_FW="no" #Drops all icmp packets to or from the firewall
#
FW_ALLOW_PING_EXT="no" #Drops all icmp packets to or from the firewall

#
# 20.)
# Allow (or don't) ICMP time-to-live-exceeded to be send from your firewall.
# This is used for traceroutes to your firewall (or traceroute like tools).
#
# Please note that the unix traceroute only works if you say "yes" to
# FW_ALLOW_INCOMING_HIGHPORTS_UDP, and windows traceroutes only if you say
# additionally "yes" to FW_ALLOW_PING_FW
#
# Choice: "yes" or "no", defaults to "no"
#
FW_ALLOW_FW_TRACEROUTE="yes"

#
# 21.)
# Allow ICMP sourcequench from your ISP?
#
# If set to yes, the firewall will notice when connection is choking, however
# this opens yourself to a denial of service attack. Choose your poison.
#
# Choice: "yes" or "no", defaults to "yes"
#
FW_ALLOW_FW_SOURCEQUENCH="yes"

#
# 22.)
# Allow/Ignore IP Broadcasts?
#
# If set to yes, the firewall will not filter broadcasts by default.
# This is needed e.g. for Netbios/Samba, RIP, OSPF where the broadcast
# option is used.
# If you do not want to allow them however ignore the annoying log entries,
# set FW_IGNORE_FW_BROADCAST to yes.
#
# Choice: "yes" or "no", defaults to "no"
#
FW_ALLOW_FW_BROADCAST="no"
#
FW_IGNORE_FW_BROADCAST="yes"


##
# END of rc.firewall2
##


That covers the local firewall on the webserver (please keep in mind that this entire tutorial is based on SUSE LINUX 7.3)

Now we integrate the special SuSE security module in the following manner:
server# cat >> /sbin/init.d/boot.local
insmod secumod hardlink=1 symlink=1 pipe=1 trace=1 systable=1 logging=1
^D
When booting, this module will be loaded with a configuration preventing Symlink, Hardlink, Pipe, and a number of other UNIX-specific attacks.

Now to the config of the apache itself.

We need to make sure nobody gains unauthorized access to data or even changes the pages. For this purpose the pages are equipped with a special protection and then the Apache is furnished with a secure configuration.
All pages must be supervised by the site administrator and should be locally write-protected for everybody except him. It is important that the web server is run under a different user than the one supervising the pages. In this way an attacker who manages to leak through the web will not be able to change the pages. Therefore a user is set up and a cron job is generated which makes sure every day that all pages belong to the site supervisor and have the correct authorizations.

server# useradd -m wwwdocs
server# cat > /etc/cron.daily/wwwdocs
#!/bin/sh
/bin/chown -R -h wwwdocs /usr/local/httpd/htdocs/*
/bin/chmod -R go-w /usr/local/httpd/htdocs/*
/bin/chmod -R a+r /usr/local/httpd/htdocs/*
^D
server# chmod 700 /etc/cron.daily/wwwdocs

Since the Apache probably has already been pre-configured, few changes will be necessary in the configuration. Of course, in the beginning the right value should be set for MinSpareServers, MaxSpareServers and StartServers in the file /etc/httpd/httpd.conf.
The option MaxClients helps to ward off connect-denial-of-service attacks. A word of caution: if this option is set to low, regular visitors will be denied access, if too high, the administrator will have difficulties logging on and taking countermeasures in the event of an attack. In order to find the correct value there is no other way than just trying.
The option ServerSignature can be switched "off" so that the software and version number is not displayed when a non-existing page is accessed, but this does not bring much since the HTTP header contains this and a lot more information.
The aliases for /hilfe/, /doc/, /cgi-bin-sdb/, /sdb/, and /manual/ should be disabled.
Here an example for what changes to the standard configuration could possibly look like: ("diff -u0")
--- httpd.conf.orig Sun Jan 19 14:35:43 2003
+++ httpd.conf Sun Jan 9 14:35:42 2003
@@ -141,2 +141,2 @@
-MinSpareServers 1
-MaxSpareServers 1
+MinSpareServers 3
+MaxSpareServers 10
@@ -148 +148 @@
-StartServers 1
+StartServers 5
@@ -157 +157 @@
-MaxClients 150
+MaxClients 100
@@ -401 +401 @@
-ServerAdmin root@localhost
+ServerAdmin webdocs@echte-domain.gr
@@ -415 +415 @@
-#ServerName server@instronics.gr
+ServerName www.echte-domain.gr
@@ -485 +485 @@
-UserDir public_html
+#UserDir public_html
@@ -646 +646 @@
-ServerSignature On
+ServerSignature Off
@@ -665,11 +664,0 @@
-Alias /hilfe/ /usr/doc/susehilf/
-Alias /doc/ /usr/doc/
-Alias /cgi-bin-sdb/ /usr/local/httpd/cgi-bin/
-Alias /sdb/ /usr/doc/sdb/
-Alias /manual/ /usr/doc/packages/apache/manual/
-
-<Location /sdb>
- Options FollowSymLinks
- AllowOverride None
-</Location>
-
@@ -697,9 +685,0 @@
-# cgi-bin for SuSE help system
-# using SetHandler
-
-<Directory /usr/lib/sdb/cgi-bin>
-AllowOverride None
-Options +ExecCGI -Includes
-SetHandler cgi-script
-</Directory>
-
@@ -981,4 +961,4 @@
-#<Location /cgi-bin/phf*>
-# Deny from all
-# ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi
-#</Location>
+<Location /cgi-bin/phf*>
+ Deny from all
+ ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi
+</location>
The activation of SSL and the generation of the certificate is described in the file /usr/doc/packages/apache/README.SuSE.

Each of the administrators should have an own user account, since it would be impossible to know who did what when working under the root identity. Besides, the incorrect entry of a command under root can effect the whole system. Therefore, operations with high levels of authority should only be done when really necessary. A direct root login over the net has already been made impossible as a result of the modifications in the configuration made with the harden_suse script, and the administration itself can only be performed in an encrypted manner with SSH. The next thing that needs to be done is to configure sudo - a program which helps the administrators to do their job while at the same time keeping a record of the commands. This program also enables a detailed authorization structure, e.g. as user oracle, user A is entitled to restart the data base and view the system log files under root, but nothing else. A user is set up for each administrator with the help of the following line:
erde# adduser -m -g trusted username
Inclusion in the group "trusted" is essential, since due to security criteria determined by harden_suse, sudo may only be used by a trusted group. Subsequently the administrator is admitted to sudo by means of the visudo program. The following line which allows the administrator to do whatever he wishes is added in the editor
username ALL=(ALL) ALL
"man 5 sudoers" defines a host of settings with which the authorizations can be restricted.
Of course it is important that the administrators use sudo and do not shift to the root identity with "su root"; for this reason, the root password should be disclosed to as few people as possible.

Log data are very important. All important log messages from the web server and the router should be sent to a central log host from where the status of the computers can be monitored. In this way it will be difficult for an attacker to hide his trail.
Additionally, it is a good idea to integrate the secure linux kernel patch by Solar Designer [13]. This makes it difficult for the attacker to exploit buffer overflows in programs.
The system can be stripped of further privileged suid and sgid programs. This is simply done by entering programs which are not supposed to have these privileges any longer in /etc/permissions.local and subsequently removing the authorizations manually or starting SuSEconfig.
This can be done until no more sgid programs and only the following suid programs are left:
-rwsr-xr-x 1 root shadow 27920 Mar 11 11:50 /usr/bin/passwd
-rwsr-x--- 1 root trusted 56600 Mar 11 18:41 /usr/bin/sudo
-rwsr-xr-x 1 root root 6132 Mar 11 09:36 /usr/lib/pt_chown
If the system has several partitions, the security level can be increased considerably by using the mount options ro (read only), nodev (no devices), nosuid (no privileged suid files) and noexec (no executable files).
Besides, the ext2 file system flags "append-only" and "imutable" (by means of the chattr command) can be used for defining the kernel capabilities in order to protect log or boot files etc. from changes.
If the server also needs to be protected from local attacks, the LILO boot loader must be equipped with a password. This is achieved by entering the following at the top of the file /etc/lilo.conf:
password=something_difficult_to_guess

restricted


Updates. A system which is not updated with the latest security patches will quickly become a target for attackers.
Having done everything that is necessary to set up a secure system, the CGI scripts pose the greatest danger. The majority of successful attacks take place by means of these scripts. A word of advice: Limit your use of CGI scripts to those which have already been publicly available and in use for some time. In case the administrators themselves write scripts, they should have these checked regularly by someone for security issues.


A web server which is both very secure and usable - something generally regarded to be contradictive - can be set up within less than 45 minutes. Much could be done to increase the level of security even more, but this system should be sufficient for most purposes.


For the sudo, AIDE, and proftpd packages please rtfm on how to use and configure them.

I know that my english is not very good, so forgive any typos, and any lines that make no sense, as this is my first tutorial ever.

I want to point out special thanks to MR. Marc Heuse for his help on the information provided here. Without him, i would not have learned as much about linux security as i do now.

Also special thanks goto the entire SuSE team ( www.suse.de )

I hope this tutorial gives you a brief introduction on how to setup a secure webserver using SuSE Linux 7.3 kernel 2.4.19


Good luck on setting up your own apache



ps. I have copy pasted a few lines out of my security book, since i had a hard time explaining it in my own words (the sudo section, and the log data section)