Instructions to set up a basic LAMP+SSH server environment
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

830 lines
42 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. Linux servers - Exercise 4
  2. ==============
  3. *Disclaimer:*
  4. --------------
  5. This exercise is a part of [Linux Server Administration (ICT4TN021, spring 2018) // Linux-palvelimet (ICT4TN021, kevät 2018)](http://www.haaga-helia.fi/fi/opinto-opas/opintojaksokuvaukset/ICT4TN021) school course organized as a part of Information Technology studies in Haaga-Helia university of Applied Sciences, Helsinki, Finland. Course lecturer [Tero Karvinen](http://terokarvinen.com/) has defined the original assignment descriptions in Finnish presented in this document in English. Answers and translations have been written by Pekka Helenius (me, ~ Fincer).
  6. *Table of contents:*
  7. --------------
  8. - [a) **Websites on the server** Make it possible to create home pages with normal user privileges in your virtual server environment.](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#a-make-it-possible-to-create-home-pages-with-normal-user-privileges-in-your-virtual-server-environment)
  9. - [EXTRA: Deleting Server field from HTTP header by updating Apache source code on Debian-based Linux distributions](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#extra-deleting-server-field-from-http-header-by-updating-apache-source-code-on-debian-based-linux-distributions)
  10. - [EXTRA: Delete suggestive HTTP error code messages from Apache HTML output by updating Apache source code](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#extra-delete-suggestive-http-error-code-messages-from-apache-html-output-by-updating-apache-source-code)
  11. - [EXTRA: Disable userdir module for user nobody to reduce server detection](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#extra-disable-userdir-module-for-user-nobody-to-reduce-server-detection)
  12. - [EXTRA: Additional protection by fine-tuning Apache HTTP headers](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#extra-additional-protection-by-fine-tuning-apache-http-headers)
  13. - [EXTRA: Additional protection by enabling ModSecurity module in Apache](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#extra-additional-protection-by-enabling-modsecurity-module-in-apache)
  14. - [b) **Default website** Set user default website to be the default website for Apache in your virtual server environment.](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#b-set-user-default-website-to-be-the-default-website-for-apache-in-your-virtual-server-environment)
  15. - [c) **Short penetration analysis** Find clues of possible penetration attempts to your web server. You can find more information about suspicious IP address without connecting them by using commands ipcalc, geoiplookup and whois, for instance.](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#c-find-clues-of-possible-penetration-attempts-to-your-web-server-you-can-find-more-information-about-suspicious-ip-address-without-connecting-them-by-using-commands-ipcalc-geoiplookup-and-whois-for-instance)
  16. - [d) **Transferring website files** Create a set of websites on your local computer and copy the sites to your web server with scp command.](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#d-create-a-set-of-websites-on-your-local-computer-and-copy-the-sites-to-your-web-server-with-scp-command)
  17. - [e) **PHP website** Set up a simple PHP webpage on your web server. For instance, you can print a remote address of the user ( $_SERVER['REMOTE_ADDR'] ) etc. Be careful if you use input forms of any kind.](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h4.md#e-set-up-a-simple-php-webpage-on-your-web-server-for-instance-you-can-print-a-remote-address-of-the-user--_serverremote_addr--etc-be-careful-if-you-use-input-forms-of-any-kind)
  18. --------------
  19. **a)** Make it possible to create home pages with normal user privileges in your virtual server environment.
  20. --------------
  21. **Answer:**
  22. Virtual server IP address is `174.138.2.190`. The server is hosted on [DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-create-your-first-digitalocean-droplet) which provides hosting services for users. Ubuntu 16.04 LTS (without DE) is used as a server platform.
  23. Ubuntu distribution hosted on DigitalOcean has custom configurations compared to Canonical version of clean Ubuntu environment. For instance, DigitalOcean has predefined different repository sources in package manager sources file `/etc/apt/sources.list` (http://mirrors.digitalocean.com/ubuntu/) and has customized configuration for Apache web server by default. Can you trust these repositories and predefined configurations as a system administrator? Can you be sure the program source codes are "clean" and do not contain malicious code patches? Are the used package repositories updated and which flags have been used to compile the binary software available there? What differences are there between the official Canonical and DigitalOcean repositories?
  24. It is good to stop to think the previous issues before looking for a third party hosting service for your server environment. Do available markets have better virtual hosting service providers and in which criteria? In small business, it can be safer to hold all the aces and set up a minimal self-hosted server using a computer (suited for your needs) such as Raspberry Pi and claim a Domain name for it from a DNS provider. If you do larger business, you need to consider your server capacity again. It can be more profitable and comfortable to buy some server space from a virtual hosting server provider.
  25. Of course, if you ever want to, you can install the server environment from scratch using rolling releases such as Arch Linux, Gentoo or 'Linux from Scratch'. However, this is not recommended approach in server environments requiring system stability over newer software. The downside is that some new features or bug/security fixes may not be implemented in older software, so keep that in mind. Some major project, however, backport security fixes to older software versions, too.
  26. Anyway,
  27. **1.** Do initial configuration for your server following the guide by Tero Karvinen:
  28. [Tero Karvinen - First Steps on a New Virtual Private Server – an Example on DigitalOcean and Ubuntu 16.04 LTS](http://terokarvinen.com/2017/first-steps-on-a-new-virtual-private-server-an-example-on-digitalocean)
  29. **2.** Connect to your new virtual private server once you have set it up. I use a predefined user name `newuser` in my server environment:
  30. ```
  31. phelenius@my-machine:~$ ssh newuser@174.138.2.190
  32. newuser@174.138.2.190's password:
  33. Welcome to Ubuntu 16.04.3 LTS (GNU/Linux x86_64)
  34. * Documentation: https://help.ubuntu.com
  35. * Management: https://landscape.canonical.com
  36. * Support: https://ubuntu.com/advantage
  37. Get cloud support with Ubuntu Advantage Cloud Guest:
  38. http://www.ubuntu.com/business/services/cloud
  39. 7 packages can be updated.
  40. 0 updates are security updates.
  41. Last login: Tue Feb 13 14:49:24 2018 from XXX.XXX.XXX.XXX
  42. newuser@goauldhost:~$
  43. ```
  44. **3.** Open default SSH TCP port 22 in your firewall:
  45. **NOTE:** Default policy for Ubuntu firewall is to deny/drop all input connections so we need to allow traffic into protocol/daemon specific ports to open up communication between this server and clients.
  46. ```
  47. newuser@goauldhost:~$ sudo ufw allow 22/tcp && sudo ufw enable
  48. ```
  49. Once you have established SSH connection to your remote server, install `apache2` package and open port `80` for it by doing the following:
  50. ```
  51. newuser@goauldhost:~$ sudo apt-get install apache2 && sudo ufw allow 80/tcp
  52. ```
  53. **4.** Enable Apache `userdir` module:
  54. ```
  55. newuser@goauldhost:~$ sudo a2enmod userdir
  56. ```
  57. **5.** Some PHP and userdir module related configurations seem to be predefined in packages provided on DigitalOcean server environment (such as `#` symbols in `/etc/apache2/mods-enabled/php7.0.conf` in order to enable PHP for user sites), unlike stated in [Exercise 3](https://github.com/Fincer/linux-server-setup/blob/master/exercises/h3.md).
  58. **6.** Restart Apache HTTP daemon (HTTPD) after enabling `userdir` module:
  59. ```
  60. newuser@goauldhost:~$ sudo systemctl restart apache2.service
  61. ```
  62. Recheck HTTP daemon state (should return `active`):
  63. ```
  64. newuser@goauldhost:~$ systemctl is-active apache2.service
  65. ```
  66. If everything seem to be running and working you can try to establish connection to the HTTP daemon server using **your local computer** (do not try this in your virtual private server environment but with an external client computer):
  67. ```
  68. phelenius@my-machine:~$ xdg-open http://174.138.2.190:80
  69. ```
  70. The IP address here refers to the virtual private server IP address.
  71. **7.** If the connection test is successful, you should see something similar to this picture:
  72. ![apache2-defaultpage](https://www.dedyprastyo.com/wp-content/uploads/2017/10/Install-Apache-di-Ubuntu-17.04-www.dedyprastyo.com_-400x400.jpg)
  73. Let's get back to the virtual server environment in our SSH session.
  74. **8.** We should hide any extra server information which is visible for clients. Add the following lines in `/etc/apache2/apache2.conf` (with sudoedit):
  75. ```
  76. TraceEnable Off
  77. ServerSignature Off
  78. ServerTokens Prod
  79. ```
  80. Description of these lines [here](https://www.petefreitag.com/item/419.cfm).
  81. Restart Apache HTTP daemon (web server):
  82. ```
  83. newuser@goauldhost:~$ sudo systemctl restart apache2.service
  84. ```
  85. **9.** Create a new user `monkey` (finnish: apina). We do not add this user to `sudo` groups, therefore denying all root access for this user:
  86. ```
  87. newuser@goauldhost:~$ sudo adduser monkey
  88. ```
  89. or equivalently:
  90. ```
  91. newuser@goauldhost:~$ sudo useradd --create-home --shell /bin/bash --user-group --uid 1006 --comment "Monkey account" --password "insert_password_here" monkey
  92. ```
  93. where
  94. - `/bin/bash` is the default shell for the new user
  95. - `1006` is the UID number for the new user. Feel free to change
  96. - `"Monkey account"` is so called "friendly" name of the account (usual syntax is: `first name surname`)
  97. - `"insert_password_here" is the password for the new user`
  98. - `monkey` is the (system) name for the new user
  99. **NOTE:** Not all Linux distributions ship with executable (wrapper) script `adduser`. In this case, either `adduser` must be installed or more primitive (but default/standard) command `useradd` should be used instead.
  100. Now, change to the default shell of user `monkey` (you can check it by executing: `grep monkey /etc/passwd`):
  101. ```
  102. newuser@goauldhost:~$ su monkey
  103. Password:
  104. monkey@goauldhost:/home/newuser$ cd
  105. monkey@goauldhost:~$ mkdir public_html
  106. ```
  107. Therefore we have created a new home site folder for the user `monkey`. Contents of this folder should be available like shown in the following picture:
  108. ![monkeysite-samplepic](https://github.com/Fincer/linux-server-setup/blob/master/images/apina-site.png)
  109. **NOTE:** As you can see, Apache doesn't give any server information in the website view, thanks for the configurations done in step 8 above.
  110. User `monkey` can add any content to his/her personal site. By default, Apache looks for any of the following files, defined in `/etc/apache2/mods-available/dir.conf` (symbolic link in folder `/etc/apache2/mods-enabled/dir.conf`):
  111. ```
  112. newuser@goauldhost:~$ ls -l /etc/apache2/mods-enabled/dir.conf
  113. lrwxrwxrwx 1 root root 26 Feb 8 10:40 /etc/apache2/mods-enabled/dir.conf -> ../mods-available/dir.conf
  114. newuser@goauldhost:~$ cat /etc/apache2/mods-enabled/dir.conf |grep -i directoryindex | awk '{$1 = ""; print $i}'
  115. index.html index.cgi index.pl index.php index.xhtml index.htm
  116. ```
  117. Permissions of folder `$HOME/public_html` of the user `monkey` are as follows:
  118. ```
  119. monkey@goauldhost:~$ stat -c "Owner: %U (user), %G (group), perms: %a // %A" $HOME
  120. Owner: monkey (user), monkey (group), perms: 775 // drwxrwxr-x
  121. ```
  122. or alternatively:
  123. ```
  124. monkey@goauldhost:~$ ls -l
  125. total 4
  126. drwxrwxr-x 2 monkey monkey 4096 Feb 13 15:35 public_html
  127. ```
  128. drwxrwxr-x
  129. 123456789 10
  130. d = directory
  131. r = read (value 4)
  132. w = write (value 2)
  133. x = execute (value 1)
  134. where
  135. ...symbols 2-4 (rwx) indicate permissions of the user `monkey` to the folder
  136. ...symbols 5-7 (rwx) indicate permissions of the (primary) group where the user `monkey` belongs to. In this case, the group is `monkey`
  137. ...symbols 8-10 (r-x) indicate permissions granted for other system users to the folder
  138. Permissions can be written in numeric form but also in symbolic form. For instance,
  139. ```
  140. 775 = rwxrwxr-x (4+2+1, 4+2+1, 4+1)
  141. ug=rwx,o=rx => rwxrwxr-x
  142. ```
  143. Take a look on the following links to get more information about Unix permissions:
  144. - [Arch Wiki - File permissions and attributes](https://wiki.archlinux.org/index.php/File_permissions_and_attributes)
  145. - [Wikipedia - Notation_of_traditional_Unix_permissions](https://en.wikipedia.org/wiki/File_system_permissions#Notation_of_traditional_Unix_permissions)
  146. - [Arch Wiki - umask](https://wiki.archlinux.org/index.php/Umask)
  147. Changing permissions is recommended to be done in symbolic mode because individual permissions can't be as flexibly be changed in numeric mode.
  148. `ls` command shows user (`monkey`) first after which group (`monkey`) is shown.
  149. The folder is accessible in public network via address `http://174.138.2.190:80/~monkey/`
  150. You can change above defined permissions with `chmod` command.
  151. - Numeric form: `chmod 775 ~/public_html`
  152. Symbolic form: `chmod ug=rwx,o=rx ~/public_html`
  153. **NOTE:** You can change permissions recursively using `-R` parameter (`chmod -R ...`)
  154. ### EXTRA: Deleting Server field from HTTP header by updating Apache source code on Debian-based Linux distributions
  155. Including Server field in HTTP header by Apache HTTP daemon (web server) is debated. [HTTP/1.1 standard specification](https://tools.ietf.org/html/rfc2616#page-141) states the following:
  156. > Note: Revealing the specific software version of the server might allow the server machine to become more vulnerable to attacks against software that is known to contain security holes. Server implementors are encouraged to make this field a configurable option.
  157. **NOTE:** Apache must be compiled from source code.
  158. Removal of Server field from HTTP header is debated in Apache developers' community (The key question here: does removal of the field actually improve any security?). More about this topic: [StackoverFlow (Can't remove Server: Apache header)](https://stackoverflow.com/questions/35360516/cant-remove-server-apache-header).
  159. **NOTE:** The following method does not work with automatic system updates via package repositories (usage of `sudo apt-get update` and `sudo apt-get upgrade` commands) because the patches binary files would be replaced by ones available in the official repositories. Therefore, each time you want to update your Apache server, you need to recompile it from source applying the patch file provided in this GitHub repository. **This method can be troublesome for system administration or contain unaccepted policy in your company. Consider using Puppet/Ansible/Chef/SaltStack or any relevant management to automate method described here.**
  160. **NOTE:** You must be aware what you are doing each time you compile software from source. Trust the source, trust the patch files (suffixes `.diff` and `.patch`) and do not do anything that can lead to unknown or troublesome bugs, malicious code execution or create new security risks.
  161. **NOTE:** We are unable to sign the package with the official maintainer key because we update Apache with our specific patch file and compile the software ourselves. Therefore we ignore any signing requirements in `dpkg-buildpackage` command (or alternatively we can use our own keys).
  162. **NOTE** Consider any policy that determines your production and/or server environment requirements. For instance: Am I allowed to install software from source code? Does my method break a (critical) component in working server environment? Etc.
  163. **NOTE: Again. Know exactly what you are about to do. As a system administrator you hold responsibility here. Do not get fired.**
  164. We have already improved security of our Apache web server by removing critical information sent to client. However, the server still gives information about its name as follows:
  165. ```
  166. newuser@goauldhost:~/source_codes/apache2$ curl -I http://localhost
  167. HTTP/1.1 200 OK
  168. Date: Sat, 17 Feb 2018 13:27:11 GMT
  169. Server: Apache
  170. Content-Type: text/html;charset=UTF-8
  171. ```
  172. We want to remove field `Server: Apache`. Multiple approaches were tested (such as `modsecurity2` module and writing line `Header unset Server` into file `/etc/apache2/apache2.conf`) without success. Therefore I ended up patching the source code of Apache web server so that the wanted field can really be removed.
  173. Download Apache source code on your Debian-based Linux distribution:
  174. ```
  175. newuser@goauldhost:~$ mkdir -p ./source_codes/apache2 && cd ./source_codes/apache2
  176. newuser@goauldhost:~/source_codes/apache2$ apt-get source apache2
  177. ```
  178. After which add [source code patch file](https://raw.githubusercontent.com/Fincer/linux-server-setup/master/patches/patch_apache_servertokens.patch) into created `$HOME/source_codes/apache2` folder.
  179. **NOTE:** I have personally created the patch file with Unix tool `diff`. The patch file is not downloaded from any suspicious website. You can always check & analyse the patch file code yourself if still hesitating.
  180. If you have a working Apache HTTP daemon (web server) environment on your Linux, please check the version of your Apache software version with the following command before compiling & installing a custom-patched Apache version:
  181. ```
  182. newuser@goauldhost:~$ dpkg -s apache2 |grep -i version
  183. Version: 2.4.18-2ubuntu3.5
  184. ```
  185. In that way we can be sure version of the downloaded source code matches with our already-installed/existing Apache environment.
  186. Once you have downloaded the source code, go to the following folder (which contains the code):
  187. ```
  188. newuser@goauldhost:~/source_codes/apache2$ cd apache2-2.4.18/
  189. ```
  190. Implement the patch file changes into the Apache source code:
  191. ```
  192. newuser@goauldhost:~/source_codes/apache2/apache2-2.4.18$ patch -Np1 -i < ../patch_apache_servertokens.patch
  193. ```
  194. Before compiling Apache web server, you must install the following build time dependencies:
  195. ```
  196. newuser@goauldhost:~/source_codes/apache2/apache2-2.4.18$ sudo apt-get install debhelper libaprutil1-dev libapr1-dev libpcre3-dev zlib1g-dev libssl-dev liblua5.1-0-dev libxml2-dev autotools-dev build-essential libnghttp2-dev liblua5.2-dev
  197. ```
  198. Compile and install the Apache web server:
  199. ```
  200. newuser@goauldhost:~/source_codes/apache2/apache2-2.4.18$ dpkg-buildpackage -rfakeroot -b -us -uc
  201. ...
  202. <compiling source code>
  203. ...
  204. <source code compiled and archived as new deb packages>
  205. ```
  206. If Apache HTTP daemon is running, stop it:
  207. ```
  208. newuser@goauldhost:~/source_codes/apache2$ sudo systemctl stop apache2.service
  209. ```
  210. It is essential to check which apache2 packages have been installed into the target system. We want to install only specific deb packages already found in the system, as multiple deb packages have been compiled by the previous command. All found Apache2 packages in the system should be replaced by the ones compiled from the Apache2 source code.
  211. System has the following Apache2 packages:
  212. ```
  213. newuser@goauldhost:~/source_codes/apache2/apache2-2.4.18$ cd ..
  214. newuser@goauldhost:~/source_codes/apache2$ dpkg --get-selections |grep apache | awk '{print $1}'
  215. apache2
  216. apache2-bin
  217. apache2-data
  218. apache2-utils
  219. libapache2-mod-php
  220. libapache2-mod-php7.0
  221. ```
  222. Then we compare the above list to the compiled deb packages:
  223. ```
  224. newuser@goauldhost:~/source_codes/apache2$ ls |grep deb
  225. apache2_2.4.18-2ubuntu3.5_amd64.deb
  226. apache2_2.4.18-2ubuntu3.5.debian.tar.xz
  227. apache2-bin_2.4.18-2ubuntu3.5_amd64.deb
  228. apache2-data_2.4.18-2ubuntu3.5_all.deb
  229. apache2-dbg_2.4.18-2ubuntu3.5_amd64.deb
  230. apache2-dev_2.4.18-2ubuntu3.5_amd64.deb
  231. apache2-doc_2.4.18-2ubuntu3.5_all.deb
  232. apache2-suexec-custom_2.4.18-2ubuntu3.5_amd64.deb
  233. apache2-suexec-pristine_2.4.18-2ubuntu3.5_amd64.deb
  234. apache2-utils_2.4.18-2ubuntu3.5_amd64.deb
  235. ```
  236. ... as a result you should install the following prerequisites:
  237. ```
  238. sudo apt-get install -y libaprutil1-dbd-sqlite3 libaprutil1-dbd-mysql libaprutil1-dbd-odbc libaprutil1-dbd-pgsql libaprutil1-ldap libmysqlclient20 libodbc1 libpq5 mysql-common
  239. ```
  240. ... after which we can install our compiled Apache2 packages with `dpkg -i` command:
  241. ```
  242. newuser@goauldhost:~/source_codes/apache2$ sudo dpkg -i apache2_2.4.18-2ubuntu3.5_amd64.deb apache2-bin_2.4.18-2ubuntu3.5_amd64.deb apache2-data_2.4.18-2ubuntu3.5_all.deb apache2-utils_2.4.18-2ubuntu3.5_amd64.deb
  243. ```
  244. If everything has succeeded you should have a working, patched Apache web server in your target system. Because the patches web server software supports `ServerTokens None` option now, we shall add this option into `/etc/apache2/apache2.conf`.
  245. ```
  246. newuser@goauldhost:~$ sudoedit /etc/apache2/apache2.conf
  247. ```
  248. Add the following lines (// just replace `ServerTokens Prod` with `ServerTokens None`):
  249. ```
  250. TraceEnable Off
  251. ServerSignature Off
  252. ServerTokens None
  253. ```
  254. **NOTE:** Any settings in `/etc/apache2/conf-available/security.conf` overrides these configuration changes.
  255. Restart Apache2 server (you must apply the patch file before doing this because the default Apache software does not implement `None` for ServerTokens):
  256. ```
  257. newuser@goauldhost:~$ sudo systemctl start apache2.service
  258. ```
  259. Check whether the configuration works:
  260. ```
  261. phelenius@my-machine:~$ curl -I http://174.138.2.190
  262. HTTP/1.1 200 OK
  263. Date: Sat, 17 Feb 2018 14:02:20 GMT
  264. Last-Modified: Wed, 14 Feb 2018 00:06:44 GMT
  265. ETag: "20b-56520e2f88f4a"
  266. Accept-Ranges: bytes
  267. Content-Length: 523
  268. Vary: Accept-Encoding
  269. Content-Type: text/html
  270. ```
  271. Therefore we have successfully deleted Server field from HTTP header.
  272. You can additionally set and unset more HTTP header fields sent to a client as follows:
  273. ```
  274. Header unset Last-Modified
  275. Header unset Accept-Ranges
  276. Header unset Vary
  277. Header unset ETag
  278. ```
  279. **NOTE:** `Header unset` settings may cause errors on starting up the server. For example, you may consider usage of `FileETag None` as a replacement for `Header unset ETag`.
  280. **NOTE:** You must be careful when unsetting fields because it affects behavior of client programs and efficiency of your server environment (performance, for instance). Remember that factors such as field order, formatting and error messages can give hints about the used server environment as well (for instance, 404 not found message).
  281. **NOTE:** The header options mentioned above work only if module `headers` has been activated (run command `sudo a2enmod headers` and restart the Apache server)
  282. More about HTTP header syntax in [Wikipedia](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields). More articles in [ETag](https://en.wikipedia.org/wiki/HTTP_ETag), [Vary: Accept-Encoding](https://blog.stackpath.com/accept-encoding-vary-important), etc.
  283. ### EXTRA: Delete suggestive HTTP error code messages from Apache HTML output by updating Apache source code
  284. [This patch file](https://raw.githubusercontent.com/Fincer/linux-server-setup/master/patches/patch_apache_disable_additional_errormsg.patch) removes the following field from Apache HTML output response if multiple errors were encountered while processing the client request:
  285. > Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
  286. and
  287. > Additionally, a 'CODE' 'MESSAGE' error was encountered while trying to use an ErrorDocument to handle the request.
  288. The message can give a hint about underlying server configuration to a (hostile) client. Applying the patch to the Apache source code will remove the message from erroneous server response. Applying the patch may give little protection against hostile clients who are trying to identify the server you're running on your website.
  289. As I have stated in the patch file, the removal can bury underneath problems in server configuration and thus hamper debugging of errors which are based on HTTP return codes. Thus, use discretion before implementing the patch in the Apache server configuration, especially in production and in other sensitive environments. This warning applies especially in Apache proxy configurations in which another server redirects error messages to the Apache proxy and multiple errors may occur.
  290. Apply the patch by doing the following in your `~/source_codes/apache2/apache2-2.4.18` folder:
  291. ```
  292. newuser@goauldhost:~/source_codes/apache2/apache2-2.4.18$ patch -Np1 -i < ../patch_apache_disable_additional_errormsg.patch
  293. ```
  294. and follow the procedures of the previous section to compile and install Apache from source code.
  295. ### EXTRA: Disable userdir module for user nobody to reduce server detection
  296. It is recommended to set `UserDir disabled nobody` in `/etc/apache2/mods-enabled/userdir.conf` file as Metasploit offensive scanning method `scanner/http/dir_scanner` can detect existence of URL/folder path `<myserver:80>/~nobody`. Minimize attack vector, and just disable the userdir module for user `nobody` on the server as follows:
  297. ```
  298. <IfModule mod_userdir.c>
  299. UserDir public_html
  300. UserDir disabled root
  301. UserDir disabled nobody
  302. ...
  303. ```
  304. The following demonstration is the view of Metasploit Framework console, using HTTP `dir_scanner` against a server:
  305. ```
  306. msf auxiliary(scanner/http/dir_scanner) > run
  307. [*] Detecting error code
  308. [*] Using code '404' as not found for AAA.BBB.XXX.CCC
  309. [+] Found http://AAA.BBB.XXX.CCC:80/~nobody/ 403 (AAA.BBB.XXX.CCC)
  310. ```
  311. ### EXTRA: Additional protection by fine-tuning Apache HTTP headers
  312. In some server environments, adding some HTTP headers may give extra protection against malicious actions by an hostile client. **NOTE:** Please keep in mind that these settings are not foolproof.
  313. At first, enable Apache `headers` module.
  314. ```
  315. sudo a2enmod headers
  316. ```
  317. Then, add the following in your Apache virtualhost (for instance, `/etc/apache2/sites-available/000-default.conf`):
  318. <VirtualHost *:80>
  319. ...
  320. <IfModule mod_headers.c>
  321. Header set X-Content-Type-Options nosniff
  322. Header always append X-Frame-Options SAMEORIGIN
  323. Header always append X-XSS-Protection 1
  324. Header always append Content-Security-Policy "frame-ancestors 'self'"
  325. </IfModule>
  326. ...
  327. </VirtualHost>
  328. > Header set X-Content-Type-Options nosniff
  329. More about this option: [Stack Overflow - What is “X-Content-Type-Options=nosniff”?](https://stackoverflow.com/questions/18337630/what-is-x-content-type-options-nosniff)
  330. > Header always append X-Frame-Options SAMEORIGIN
  331. More protection against [Clickjacking attacks](https://www.keycdn.com/blog/x-frame-options/#Clickjacking)
  332. More about this option:
  333. - [keycdn.com - X-Frame-Options - How to Combat Clickjacking](https://www.keycdn.com/blog/x-frame-options/#X-Frame-Options-Directives)
  334. - [OWASP - Clickjacking Defense Cheat Sheet](https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet)
  335. > Header always append X-XSS-Protection 1
  336. More about this option: [keycdn.com - X-XSS-Protection - Preventing Cross-Site Scripting Attacks](https://www.keycdn.com/blog/x-xss-protection/)
  337. > Header always append Content-Security-Policy "frame-ancestors 'self'"
  338. Another clickjacking attack prevention (CSP 2.0)
  339. More about this option: [OWASP - Content Security Policy Cheat Sheet: Preventing Clickjacking (CSP 2.0)](https://www.owasp.org/index.php/Content_Security_Policy_Cheat_Sheet#Preventing_Clickjacking)
  340. ### EXTRA: Additional protection by enabling ModSecurity module in Apache
  341. More security features can be added to Apache server by using [ModSecurity Apache module by Trustwave SpiderLabs](https://www.modsecurity.org/about.html). The module is released under [Apache Software License version 2](http://www.apache.org/licenses/LICENSE-2.0.txt). A brief description of the module, quoted from the website:
  342. > ModSecurity is a toolkit for real-time web application monitoring, logging, and access control.
  343. There is an additional ModSecurity ruleset available by OWASP. You can read more about it on [OWASP website: ModSecurity Core Rule Set Project](https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project)
  344. At first, make sure that Apache `security` module is installed:
  345. ```
  346. [[ $(dpkg --get-selections | grep libapache2-mod-security2) ]] || sudo apt-get update && sudo apt-get install -y libapache2-mod-security2 modsecurity-crs
  347. ```
  348. Then, enable the module:
  349. ```
  350. sudo a2enmod security2
  351. ```
  352. **NOTE:** Before blindly accepting `security` module, please take extra care if your Apache server is in production or in sensitive environment where stability is absolutely required without nasty or troublesome interruptions!
  353. **NOTE:** If you decided to adapt some of the following `security` module rules, you should identify which of these settings are relevant *in your server environment*.
  354. **NOTE:** The following ruleset is a loose reference which uses the settings by [Ask Apache - Mod_Security .htaccess tricks website](https://www.askapache.com/htaccess/modsecurity-htaccess-tricks/)
  355. Add the following in your VirtualHost configuration (for instance, `/etc/apache2/sites-available/000-default.conf`):
  356. ```
  357. <VirtualHost *:80>
  358. ...
  359. <IfModule security2_module.c>
  360. SecDataDir /var/cache/modsecurity
  361. IncludeOptional /etc/modsecurity/*.conf
  362. IncludeOptional /usr/share/modsecurity-crs/owasp-crs.load
  363. # Enable ModSecurity
  364. SecRuleEngine On
  365. # Sends matching requests a 405 Method Not Allowed Status Code
  366. SecFilterSelective REQUEST_METHOD "!^(GET|HEAD|POST)$" "deny,auditlog,status:405"
  367. # Do not accept GET or HEAD requests with bodies
  368. SecFilterSelective REQUEST_METHOD "^(GET|HEAD)$" chain
  369. SecFilterSelective HTTP_Content-Length "!^$"
  370. # Require Content-Length to be provided with
  371. # every POST request
  372. SecFilterSelective REQUEST_METHOD "^POST$" chain
  373. SecFilterSelective HTTP_Content-Length "^$"
  374. # Don't accept transfer encodings we know we don't handle
  375. SecFilterSelective HTTP_Transfer-Encoding "!^$"
  376. # Should mod_security inspect POST payloads
  377. SecFilterScanPOST On
  378. # Make sure that URL encoding is valid
  379. SecFilterCheckURLEncoding On
  380. # Only log suspicious requests
  381. SecAuditEngine RelevantOnly
  382. # Unicode encoding check
  383. SecFilterCheckUnicodeEncoding Off
  384. </IfModule>
  385. ...
  386. </VirtualHost>
  387. ```
  388. **b)** Set user default website to be the default website for Apache in your virtual server environment.
  389. --------------
  390. **Answer:**
  391. Let's begin from the final state of the previous answer. We have created a user `monkey` in our server computer. This user has a website URL `174.138.2.190:80/~monkey` which is accessible outside the server computer, too.
  392. **1.** Remove default webpage of Apache web server, and move `DocumentRoot` to point to directory `$HOME/public_html` of user `monkey`, after which restart Apache service daemon.
  393. ```
  394. newuser@goauldhost:~$ sudo sed -i 's?DocumentRoot /var/www/html?DocumentRoot /home/monkey/public_html?' /etc/apache2/sites-available/000-default.conf
  395. ```
  396. We can disable folder path `/var/www` commenting out the following lines (inserting `#` comment symbols) in file `/etc/apache2/apache2.conf` (use command `sudoedit /etc/apache2/apache2.conf`, for instance):
  397. ```
  398. #<Directory /var/www/>
  399. # Options Indexes FollowSymLinks
  400. # AllowOverride None
  401. # Require all granted
  402. #</Directory>
  403. ```
  404. Restart Apache web server daemon:
  405. ```
  406. newuser@goauldhost:~$ sudo systemctl restart apache2.service
  407. ```
  408. Go to the following IP address with your **local computer** (use HTTP port `80`):
  409. ```
  410. xdg-open http://174.138.2.190:80
  411. ```
  412. The opening view should be as follows:
  413. ![emptypage-sample](https://github.com/Fincer/linux-server-setup/blob/master/images/empty-page-sample.png)
  414. **2.** Create a new file `index.html` in the directory `$HOME/public_html` of user `monkey` (where `$HOME is folder path `/home/monkey/`)
  415. ```
  416. newuser@goauldhost:~$ su monkey
  417. Password:
  418. monkey@goauldhost:/home/newuser$ cd
  419. monkey@goauldhost:~$ echo -e '<!DOCTYPE html>\n <html>\n \t<head>\n \t\t<title>Testi</title>\n \t</head>\n \t<body>\n \t\t<h1>Testi</h1>\n \t</body>\n </html>\n' > ~/public_html/index.html
  420. ```
  421. **3.** We should redirect all `index.html` traffic to the folder root `/home/monkey/public_html/`. This can be achieved by creating hidden page-related control file `.htaccess` file to the directory root.
  422. ```
  423. monkey@goauldhost:~$ cd public_html
  424. monkey@goauldhost:~/public_html$ touch .htaccess
  425. monkey@goauldhost:~/public_html$ echo -e '<IfModule mod_rewrite.c>\n\tRewriteEngine On\n\tRewriteBase /\n\tRewriteRule ^index\.html$ / [NC,R,L]\n</IfModule>' | tee -a ./.htaccess
  426. ```
  427. Reactivate Apache module `rewrite`. We shall switch our user because user `monkey` doesn't have `sudo` rights at this point:
  428. ```
  429. monkey@goauldhost:~/public_html$ su newuser
  430. Password:
  431. newuser@goauldhost:/home/monkey/public_html$ sudo a2enmod rewrite
  432. Enabling module rewrite.
  433. To activate the new configuration, you need to run:
  434. service apache2 restart
  435. newuser@goauldhost:/home/monkey/public_html$ sudo systemctl restart apache2.service
  436. ```
  437. Your Apache web server should redirect all traffic of `http://174.138.2.190:80/index.html` to address `http://174.138.2.190:80/`
  438. **c)** Find clues of possible penetration attempts to your web server. You can find more information about suspicious IP address without connecting them by using commands ipcalc, geoiplookup and whois, for instance.
  439. --------------
  440. **Answer:**
  441. The key principle to check any malicious activity is to check system log files, mainly `/var/log/apache/access.log` and `/var/log/apache/error.log` (Apache). Malicious SSH attempts may be checked in `/var/log/auth.log`. Other relevant log files must be considered as important, too.
  442. At the time of writing this answer, the Apache web server was running bit over a week period. However, there were no any webpage deployed during that time, and therefore my web server hadn't created any major log entries. However, I noticed one suspicious connection attempt to setup.php file of phpMyAdmin software, although the software was not installed. The lookup was done by checking web server log file `/var/log/apache2/access.log`. The log entry itself was as follows:
  443. ```
  444. 66.118.142.165 - - [13/Feb/2018:14:43:58 +0000] "HEAD /phpmyadmin/scripts/setup.php HTTP/1.0" 404 159 "-" "-"
  445. ```
  446. We shall analyze the logged IP address (+ download a georeferred IP database to determine more specific geolocation of the source by using `wget` command):
  447. ```
  448. newuser@goauldhost:~$ sudo apt-get -y install geoip-bin
  449. newuser@goauldhost:~$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
  450. newuser@goauldhost:~$ gunzip GeoLiteCity.dat.gz
  451. newuser@goauldhost:~$ OBSIP=66.118.142.165
  452. newuser@goauldhost:~$ echo -e "Server Geolocation:\n$(geoiplookup -f /home/newuser/GeoLiteCity.dat $OBSIP)\n\n$(nslookup $OBSIP)\n\nDNS Name:\n$(dig +short -x $OBSIP)" && unset OBSIP
  453. ```
  454. Output is as follows:
  455. ```
  456. Server Geolocation:
  457. GeoIP City Edition, Rev 1: US, FL, Florida, Tampa, 33611, 27.886700, -82.511703, 539, 813
  458. Server: 67.207.67.2
  459. Address: 67.207.67.2#53
  460. Non-authoritative answer:
  461. 165.142.118.66.in-addr.arpa name = 66-118-142-165.static.sagonet.net.
  462. Authoritative answers can be found from:
  463. DNS Name:
  464. 66-118-142-165.static.sagonet.net.
  465. ```
  466. The log entry tells us that connection to page `http://174.138.2.190:80/phpmyadmin/scripts/setup.php` was tried to be established. The server responded with code 404 (HTTP_NOT_FOUND), indicating that the address couldn't be found. It is seen that user agent string of `66.118.142.165` is empty (just a line). It is known that the user agent string can very easily be customized.
  467. HTTP [HEAD method](http://condor.depaul.edu/dmumaugh/readings/handouts/SE435/HTTP/node14.html) were used in the connection attempt. The HTTP HEAD method is more suitable for quick file existence look-ups than HTTP GET method because only the file existence is checked, leading to decreased data transfer rates between a server and a client. The HEAD method is usually used for caching documents (data). A client program just tries to download metadata of the request document from a server. [Apache web server does not return the message response body while answering to the client program with the HTTP HEAD method.](https://hc.apache.org/httpclient-3.x/methods/head.html).
  468. the HEAD method can be "disabled" by adding the following lines into 1) file `~/public_html/.htaccess` (in the case of this assignment) 2) or into file `/etc/apache2/sites-available/000-default.conf` 3) or any site-specific configuration file in Apache's `sites-available` folder 4) or any `.htaccess` file in a website directory root:
  469. ```
  470. RewriteEngine on
  471. RewriteCond %{THE_REQUEST} !^(POST|GET)\ /.*\ HTTP/1\.1$
  472. RewriteRule .* - [F,L]
  473. ```
  474. The original answer [here](https://www.linuxquestions.org/questions/linux-security-4/disabling-head-options-http-methods-in-apache-webserver-763347/#post4511023)
  475. It is understandable that line `RewriteEngine on` doesn't need to be determined twice and adding this code requires re-enabling of Apache rewrite module.
  476. I have had a Debian-based web server (LAMP) environment in the past years. I have included Apache `/var/log/apache/access.log` parts of that web server environment here (year 2014):
  477. [Apache - access.log, example](https://github.com/Fincer/linux-server-setup/blob/master/other/apache-log-sample)
  478. The log file reveals many suspicious connection attempts from Thailand and Netherlands, for instance.
  479. The most memorable log entry from the past years was, however, a penetration attempt by Romanian hacker/bot group and it looked like as follows:
  480. ```
  481. 4.125.148.79 - - [07/Aug/2013:20:53:35 +0400] "GET /w00tw00t.at.blackhats.romanian.anti-sec:) HTTP/1.1" 404 142 "-" "ZmEu"
  482. ```
  483. **d)** Create a set of websites on your local computer and copy the sites to your web server with scp command.
  484. --------------
  485. **Answer:**
  486. **1.** Let's create the required websites locally, after which the upload is done with user `newuser`. I have used pre-created websites in this assignment. The upload is done with my Arch Linux computer using required SSH protocol:
  487. ```
  488. [13/02/2018 21:04:16 - fincer: ~ ]$ scp /home/fincer/Documents/website/website_1.03_fincer.zip newuser@174.138.2.190:./
  489. The authenticity of host '174.138.2.190 (174.138.2.190)' can't be established.
  490. ECDSA key fingerprint is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
  491. Are you sure you want to continue connecting (yes/no)? yes
  492. Warning: Permanently added '174.138.2.190' (ECDSA) to the list of known hosts.
  493. newuser@174.138.2.190's password:
  494. website_1.03_fincer.zip 100% 656KB 655.8KB/s 00:01
  495. [13/02/2018 21:04:32 - fincer: ~ ]$
  496. ```
  497. **2.** Modify Apache default webpage address to point to `/home/newuser/public_html/`:
  498. ```
  499. newuser@goauldhost:~$ sudo sed -i 's?DocumentRoot /home/monkey/public_html?DocumentRoot /home/newuser/public_html?' /etc/apache2/sites-available/000-default.conf
  500. newuser@goauldhost:~$ sudo systemctl restart apache2.service
  501. ```
  502. **3.** Because `/home/newuser/public_html/` is empty (checked with `ls` command), we shall extract uploaded `website_1.03_fincer.zip` to that directory.
  503. ```
  504. newuser@goauldhost:~$ sudo apt-get update && sudo apt-get install unzip
  505. newuser@goauldhost:~$ mv website_1.03_fincer.zip ./public_html/ && cd ./public_html
  506. newuser@goauldhost:~$ unzip website_1.03_fincer.zip
  507. ```
  508. **4.** It should be possible to open the website using URL `174.138.2.190`, and the website should look like the following:
  509. ![website-sample](https://github.com/Fincer/linux-server-setup/blob/master/images/pekkahh-website.png)
  510. **5.** Let's copy another website sample into folder `$HOME/public_html/` of user `monkey`:
  511. ```
  512. [13/02/2018 22:01:40 - fincer: ~ ]$ scp /home/fincer/Documents/server_site.tar.xz monkey@174.138.2.190:./public_html/
  513. ```
  514. **6.** Let's establish a new SSH connection to the virtual server computer with user `monkey`:
  515. ```
  516. [13/02/2018 22:04:23 - fincer: ~ ]$ ssh monkey@174.138.2.190
  517. ```
  518. **7.** In the virtual web server computer terminal, go to `$HOME/public_html/` of user `monkey`, extract `server_site.tar.xz` and put the extracted files into correct places in the directory hierarchy. Rename old `index.html` file to `index.html.old`
  519. ```
  520. monkey@goauldhost:~/public_html$ mv index.html index.html.old
  521. monkey@goauldhost:~/public_html$ tar xf server_site.tar.xz
  522. monkey@goauldhost:~/public_html$ mv ./server_site/* ./
  523. monkey@goauldhost:~/public_html$ rm -Rf ./{server_site,server_site.tar.xz}
  524. ```
  525. (you could have just used one * symbol in the previous rm command because the equal name syntax, i.e. `rm -Rf ./server_site*`)
  526. The deployed website can be viewed in URL address `http://174.138.2.190:80/~monkey`, and they look as follows (this example is a work time // wage calculator):
  527. ![workprice-samplesite](https://github.com/Fincer/linux-server-setup/blob/master/images/workprice-site_example.png)
  528. **NOTE:** There are differences in the URL due to language reasons (`~apina` translates from finnish to english as `~monkey`)
  529. **e)** Set up a simple PHP webpage on your web server. For instance, you can print a remote address of the user ( $_SERVER['REMOTE_ADDR'] ) etc. Be careful if you use input forms of any kind.
  530. --------------
  531. **Answer:**
  532. In this answer, I add a PHP-based BMI calculator (Body Mass Index) to my website. For this purpose, two files were created: `bmicalc.html` and `bmicalc.php` which both are uploaded to the virtual web server with the following command, executed at the **local computer**:
  533. ```
  534. phelenius@my-machine:~$ scp $HOME/public_html/bmi-index/{bmicalc.php,bmicalc.html} newuser@174.138.2.190:./public_html/
  535. newuser@174.138.2.190's password:
  536. bmicalc.php 100% 3051 3.0KB/s 00:00
  537. bmicalc.html 100% 523 0.5KB/s 00:00
  538. ```
  539. The following image demonstrates a web browser view of URL address `174.138.2.190/bmicalc.html`.
  540. - On the left side: the source code of the HTML page.
  541. - On the right side: server-side "raw" PHP source code which is not seen by the client program, our web browser in this case (PHP code = server-side execution, i.e. only web server sees the code, JavaScript code = client-side execution, i.e. client can see the code, too)
  542. ![bmicalc-sample](https://github.com/Fincer/linux-server-setup/blob/master/images/bmicalc-sample.png)
  543. **Edit** The following changes has been done after answering the assignment:
  544. - PHP-related HTTP method GET has been changed to POST method afterwards because usage of the GET method leads to visible input values in a web browser URL field. This doesn't happen when using the POST method.
  545. - Implementation of server-side solutions which restrict user accessibility to other web server directories and files.
  546. - PHP code has been merged with the HTML document, i.e. there is no additional `.php` file in the web server anymore.