Difference between revisions of "Short Notes on Security"

From PaskvilWiki
Jump to: navigation, search
(.htaccess and mod_rewrite Tricks)
(Using RSync together with SSH)
 
(4 intermediate revisions by one user not shown)
Line 1: Line 1:
== Apache ==
+
== Password Generators ==
  
=== Note - serving of local files ===
+
* '''PHP''' - replace the '16' with length of the generated password (28 is most you can get):
 +
<pre>$password = substr(str_replace(array('$1$', '$2$', '$2a$', '$', '.', '/'), '', crypt(php_uname() . microtime())), 0, 16);</pre>
 +
or, terminal version:
 +
<pre>$ php -r "echo substr(str_replace(array('$1$', '$2$', '$2a$', '$', '.', '/'), '', crypt(php_uname() . microtime())), 0, 16);"
 +
1hlNxRwBr4mCZWQF</pre>
  
'''Note''': Often the initial installation of Apache has <tt>&lt;Directory /&gt;</tt> directive (directive for the root of the filesystem) set to "Allow from All", in '''[Apache config dir]/sites-available/default'''! This means that server can server '''any''' file from the file system, not just the files in the ''htdocs'' document folder, which you typically want!
+
* '''Bash''' - replace the '64' with length of the generated password (no real limit here), and change the characters class in <tt>tr -d</tt> as you please, to control what characters can be contained in the password; the characters class presented here are all characters that are treated as a part of the word in terminal (i.e. you can double-click the word and it gets selected as a whole):
 +
<pre>$ cat /dev/urandom | tr -d -c "a-zA-Z0-9@#%&\-\_+=:,.?/" | head -c 64; echo
 +
uQ,XGSG4qPtE4.&UQT,jPA#=a8j-mhy+qjQUg:m#s7g1@c2-#J8D-,3zQFd+o_-W</pre>
  
To avoid this, simply change this to "Deny from All".
+
== SSH Access using pubkey's for Authentication ==
  
=== Self-Signed SSL Certificate ===
+
You can make your system's remote login way safer with just 3 simple steps:
 +
# Create your public-private key pair of files.
 +
# Register your public key on the server you want to access.
 +
# [''optional and recommended''] Allow only login using the pubkey on the server.
  
They might not pass as customer-friendly - in fact, if you need https/ssl for customer communication, you should always use signed certificates, as those do induce trust - but often you have private sections/domains/sites where self-signed is just fine... or you might just wanna test the ssl while waiting for the signed certificate.
+
=== Create public-private key pair ===
  
Here are only listed steps to get to your certificate; for details and explanations, see e.g. [http://www.akadia.com/services/ssh_test_certificate.html akadia.com].
+
To generate the public-private key pair, use <tt>ssh-keygen -t rsa</tt>.
  
<pre># openssl genrsa -des3 -out server.key 1024
+
You’ll be prompted for where to save the pubkeys, then for passphrase (either empty, or 5+ letters), repeat if non-empty, and the keys get generated. Just as with passwords, it's important to use strong passphrases.
# openssl req -new -key server.key -out server.csr
+
# cp server.key server.key.org
+
# openssl rsa -in server.key.org -out server.key
+
# openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
+
# cp server.crt /etc/apache2/cert/ssl.crt
+
# cp server.key /etc/apache2/cert/ssl.key
+
# chmod 400 /etc/apache2/cert/ssl.crt /etc/apache2/cert/ssl.key</pre>
+
  
=== Enable SSL/HTTPS in Apache ===
+
You should <tt>chmod 600</tt> both key files, and be very careful about them.
  
'''HowTo''': Use the following virtual host definition:
+
Highly recommended is to hold them in a [http://www.truecrypt.org/ truecrypt] partition or the like, if you carry them around. If you need to write down the passphrase somewhere, again, either use [http://www.truecrypt.org/ truecrypt], or use <tt>vim -x</tt>, or the likes. Don't forget, chain is only as strong as is its weakest link.
  
<pre><VirtualHost *:443>
+
=== Setup the server for key-based login ===
    ServerName ssl-name
+
    DocumentRoot /var/www/ssl/root
+
    SSLEngine on
+
    SSLCertificateFile /etc/apache2/server.crt
+
    SSLCertificateKeyFile /etc/apache2/server.key
+
    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
+
</VirtualHost></pre>
+
  
where ''certificate file'' and the ''certificate key file'' are either authority-signed or self-signed certificate files (see above), and add
+
Transfer the created ''*.pub'' file (typically called ''id_rsa.pub'') to the server you want to log into remotely. Do '''not''' transfer the private part of the pair (typically called ''id_rsa'')!!
  
<pre>NameVirtualHost *:443
+
Register the key on the server by appending it to list of authorized keys for the user this key belongs to, like this:
Listen 443</pre>
+
cat id_rsa.pub >> /home/''user''/.ssh/authorized_keys
 +
The <tt>.ssh/authorized_keys</tt> file should of course also be <tt>chmod 600</tt>, and the <tt>/home/''user''/.ssh</tt> folder <tt>chmod 700</tt>.
  
to '''/etc/apache2/ports.conf''' and restart Apache.
+
==== Test it ====
  
=== .htaccess and mod_rewrite Tricks ===
+
Now, you should be able to login to the server using
 +
ssh -i ''privatekey'' ''user''@''server''
 +
e.g. ssh -i ~/.ssh/id_rsa user@example.com
  
Mostly based on [http://www.queness.com/post/5421/17-useful-htaccess-tricks-and-tips 17 Useful .htaccess Tricks and Tips]
+
Server verifies your identity based on the public key, but to login you need both ''id_rsa'' and ''id_rsa.pub''.
  
==== General ====
+
=== Fortify the server (optional, ''root'' rights required) ===
  
'''1. Set Timezone'''
+
Once all is up and running, and you've tested the login properly, you may choose to disable password-based login.
-----
+
  
<pre>SetEnv TZ Australia/Melbourne</pre>
+
Edit the <tt>/etc/ssh/sshd_config</tt> file (or <tt>/usr/local/etc/sshd_config</tt> on BSD’s). Add/update the following lines:
[http://www.php.net/manual/en/timezones.php List of timezones].
+
PasswordAuthentication no
 +
RSAAuthentication yes
 +
PubkeyAuthentication yes
 +
AuthorizedKeysFile %h/.ssh/authorized_keys
 +
Then restart <tt>`ssh`</tt> – using <tt>/etc/init.d/ssh restart</tt> (or <tt>/usr/local/etc/rc.d/ssh restart</tt> on BSD’s).
  
'''2. SEO Friendly 301 Permanent Redirects'''
+
You may also choose to disable ''root'' login, allowing only regular users to login, and then use <tt>sudo</tt> to become root. Simply add/update in <tt>/etc/ssh/sshd_config</tt>:
-----
+
PermitRootLogin no
  
Modern search engines have the capability to detect 301 Permanent Redirects and update its existing records.
+
== Using RSync together with SSH ==
  
<pre>Redirect 301 http://www.domain.com/home http://www.domain.com/</pre>
+
Using password-based authentication:
 
+
$ rsync -avz -e ssh ''user''@''server'':/''remote''/''dir'' /''this''/''dir''/
'''3. Skip the Download Dialogue'''
+
Using pubkey-based authentication:
-----
+
$ rsync -avz -e "ssh -i /''path''/''to''/id_rsa" ''user''@''server'':/''remote''/''dir'' /''this''/''dir''/
 
+
The following defines given types as octet-stream, thus making it "only to download"; clicking the link to such resource will skip "open / save" dialog and will start download immediately.
+
 
+
<pre>AddType application/octet-stream .pdf
+
AddType application/octet-stream .zip
+
AddType application/octet-stream .mov</pre>
+
 
+
'''4. Skip or Force www.'''
+
-----
+
 
+
One of the SEO guidelines is, make sure there is only one URL pointing to your website.
+
 
+
To force URL's without www.:
+
 
+
<pre>RewriteEngine On
+
RewriteBase /
+
RewriteCond %{HTTP_HOST} ^www.domain.com [NC]
+
RewriteRule ^(.*)$ http://domain.com/$1 [L,R=301]</pre>
+
 
+
To force www. in the URL:
+
 
+
<pre>RewriteEngine On
+
RewriteBase /
+
RewriteCond %{HTTP_HOST} ^domain.com [NC]
+
RewriteRule ^(.*)$ http://www.domain.com/$1 [L,R=301]</pre>
+
 
+
'''5. Custom Error Pages'''
+
-----
+
 
+
<pre>ErrorDocument 401 /error/401.php
+
ErrorDocument 403 /error/403.php
+
ErrorDocument 404 /error/404.php
+
ErrorDocument 500 /error/500.php</pre>
+
 
+
'''6. Compress Files'''
+
-----
+
 
+
You need to have <tt>deflate</tt> module installed and enabled.
+
 
+
<pre>AddOutputFilterByType DEFLATE text/plain
+
AddOutputFilterByType DEFLATE text/html
+
AddOutputFilterByType DEFLATE text/xml
+
AddOutputFilterByType DEFLATE text/css
+
AddOutputFilterByType DEFLATE application/xml
+
AddOutputFilterByType DEFLATE application/xhtml+xml
+
AddOutputFilterByType DEFLATE application/rss+xml
+
AddOutputFilterByType DEFLATE application/javascript
+
AddOutputFilterByType DEFLATE application/x-javascript</pre>
+
 
+
'''7. Cache Files'''
+
-----
+
 
+
The following example sets caching of multimedia files to 30 days:
+
 
+
<pre><FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf|js|css|pdf)$">
+
  Header set Cache-Control "max-age=2592000"
+
</FilesMatch></pre>
+
 
+
'''8. Disable Caching for Certain File Type'''
+
-----
+
 
+
The following example disables caching of scripts:
+
 
+
<pre><FilesMatch ".(pl|php|cgi|spl|scgi|fcgi)$">
+
  Header unset Cache-Control
+
</FilesMatch></pre>
+
 
+
'''9. Redirect (Sections) to https://'''
+
-----
+
 
+
The following forces /login and /signup sections of your site to use https.
+
 
+
Of course, it's recommendable that you have a signed SSL certificate.
+
 
+
<pre>RewriteEngine on
+
RewriteCond %{HTTPS} =off
+
RewriteCond %{REQUEST_URI} /login [NC,OR]
+
RewriteCond %{REQUEST_URI} /signup [NC]
+
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]</pre>
+
 
+
'''10. Simple MVC using .htaccess'''
+
-----
+
 
+
You can redirect all requests to a single script file, and serve content based on REQUEST_URI:
+
 
+
<pre>RewriteEngine On
+
RewriteRule !robots\.txt|\.(js|ico|gif|jpg|png|css|flv|swf)$ index.php</pre>
+
 
+
'''11. Provide Different Page Versions based on User Agent'''
+
-----
+
 
+
You can provide different versions of your site for different browsers (e.g. ''links'' as a text-based browser, and for mobile devices):
+
 
+
<pre>RewriteEngine On
+
 
+
# MSIE
+
RewriteCond %{HTTP_USER_AGENT} ^Mozilla/4(.*)MSIE
+
RewriteRule ^index\.html$ /index.ie.html [L]
+
 
+
# Netscape / Mozilla
+
RewriteCond %{HTTP_USER_AGENT} ^Mozilla/5(.*)Gecko
+
RewriteRule ^index\.html$ /index.full.html [L]
+
 
+
# Lynx, text based
+
RewriteCond %{HTTP_USER_AGENT} ^Lynx/
+
RewriteRule ^index\.html$ /index.light.html [L]
+
 
+
# Mobile version of your site
+
RewriteCond %{HTTP_USER_AGENT} ^.*(iPad|iPhone).*$
+
RewriteRule ^(.*)$ http://ipad.domain.com [R=301]
+
 
+
# All other
+
RewriteRule ^index\.html$ /index.medium.html [L]</pre>
+
 
+
==== Security ====
+
 
+
'''1. Hotlinking Protection with .htaccess'''
+
-----
+
 
+
Block all multimedia file requests that do not come from direct link or from your site:
+
 
+
<pre>RewriteEngine On
+
RewriteCond %{HTTP_REFERER} !^$
+
RewriteCond %{HTTP_REFERER} !^http://(www.)?domain.com/.*$ [NC]
+
RewriteRule .(gif|jpg|swf|flv|png)$ /no-hotlink.html [R=302,L]</pre>
+
 
+
'''2. Prevent Hacks'''
+
-----
+
 
+
Block some common malicious URL hacks:
+
 
+
<pre>RewriteEngine On
+
 
+
# proc/self/environ? no way!
+
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
+
 
+
# Block out any script trying to set a mosConfig value through the URL
+
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
+
 
+
# Block out any script trying to base64_encode crap to send via URL
+
RewriteCond %{QUERY_STRING} base64_encode.*(.*) [OR]
+
 
+
# Block out any script that includes a <script> tag in URL
+
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
+
 
+
# Block out any script trying to set a PHP GLOBALS variable via URL
+
RewriteCond %{QUERY_STRING} GLOBALS(=|[|\%[0-9A-Z]{0,2}) [OR]
+
 
+
# Block out any script trying to modify a _REQUEST variable via URL
+
RewriteCond %{QUERY_STRING} _REQUEST(=|[|\%[0-9A-Z]{0,2})
+
 
+
# Send all blocked request to page with 403 Forbidden error!
+
RewriteRule ^(.*)$ no-way.html [F,L]</pre>
+
 
+
'''3. Block Access to Your .htaccess File'''
+
-----
+
 
+
<pre># secure .htaccess file
+
<Files .htaccess>
+
  Order Allow,Deny
+
  Deny from All
+
</Files>
+
 
+
# prevent viewing of a specific file
+
<Files secretfile.jpg>
+
  Order Allow,Deny
+
  Deny from All
+
</Files>
+
 
+
# multiple files / file types
+
<FilesMatch ".(htaccess|htpasswd|ini|phps|fla|psd|log|sh)$">
+
  Order Allow,Deny
+
  Deny from All
+
</FilesMatch></pre>
+
 
+
'''4. Rename .htaccess Files'''
+
-----
+
 
+
<pre>AccessFileName htacc.ess</pre>
+
 
+
'''5. Disable Directory Browsing'''
+
-----
+
 
+
<pre># disable directory browsing
+
Options All -Indexes
+
 
+
# enable directory browsing
+
Options All +Indexes</pre>
+
 
+
'''6. Change Default Index Page'''
+
-----
+
 
+
<pre>DirectoryIndex my-home.html</pre>
+
 
+
'''7. Block Unwanted Visitor based on Referring Domain'''
+
-----
+
 
+
<pre># block visitors referred from indicated domains
+
RewriteEngine on
+
RewriteCond %{HTTP_REFERER} scumbag.com [NC,OR]
+
RewriteCond %{HTTP_REFERER} wormhole.com [NC,OR]
+
RewriteRule .* - [F]</pre>
+
 
+
'''8. Blocking Request based on User-Agent Header'''
+
-----
+
 
+
<pre># block certain bots and spiders
+
SetEnvIfNoCase ^User-Agent$ .*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures) HTTP_SAFE_BADBOT
+
SetEnvIfNoCase ^User-Agent$ .*(libwww-perl|aesop_com_spiderman) HTTP_SAFE_BADBOT
+
Deny from env=HTTP_SAFE_BADBOT</pre>
+
 
+
'''9. Secure Directories by Disabling Execution of Scripts'''
+
-----
+
 
+
<pre>AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
+
Options -ExecCGI</pre>
+
 
+
== Other ==
+
 
+
==== Password Generators ====
+
 
+
* '''PHP''' - replace the '16' with length of the generated password (28 is most you can get):
+
<pre>$password = substr(str_replace(array('$1$', '$2$', '$2a$', '$', '.', '/'), '', crypt(php_uname() . microtime())), 0, 16);</pre>
+
or, terminal version:
+
<pre>$ php -r "echo substr(str_replace(array('$1$', '$2$', '$2a$', '$', '.', '/'), '', crypt(php_uname() . microtime())), 0, 16);"; echo
+
1hlNxRwBr4mCZWQF</pre>
+
 
+
* '''Bash''' - replace the '64' with length of the generated password (no real limit here), and change the characters class in <tt>tr -d</tt> as you please, to control what characters can be contained in the password; the characters class presented here are all characters that are treated as a part of the word in terminal (i.e. you can double-click the word and it gets selected as a whole):
+
<pre>$ cat /dev/urandom | tr -d -c "a-zA-Z0-9@#%&\-\_+=:,.?/" | head -c 64; echo
+
uQ,XGSG4qPtE4.&UQT,jPA#=a8j-mhy+qjQUg:m#s7g1@c2-#J8D-,3zQFd+o_-W</pre>
+
  
 
== External Links ==
 
== External Links ==
 
=== Apache ===
 
 
* [http://httpd.apache.org/docs/2.0/howto/htaccess.html .htaccess files in Apache2]
 
* [http://httpd.apache.org/docs/2.0/programs/htpasswd.html htpasswd utility in Apache2]
 
* [http://httpd.apache.org/docs/2.0/howto/auth.html Authentication, Authorization and Access Control in Apache2]
 
 
=== Other ===
 
  
 
* [http://blogs.sun.com/jkini/entry/how_to_scp_scp_and How To scp, ssh and rsync without prompting for password]
 
* [http://blogs.sun.com/jkini/entry/how_to_scp_scp_and How To scp, ssh and rsync without prompting for password]

Latest revision as of 16:05, 18 September 2012

Password Generators

  • PHP - replace the '16' with length of the generated password (28 is most you can get):
$password = substr(str_replace(array('$1$', '$2$', '$2a$', '$', '.', '/'), '', crypt(php_uname() . microtime())), 0, 16);

or, terminal version:

$ php -r "echo substr(str_replace(array('$1$', '$2$', '$2a$', '$', '.', '/'), '', crypt(php_uname() . microtime())), 0, 16);"
1hlNxRwBr4mCZWQF
  • Bash - replace the '64' with length of the generated password (no real limit here), and change the characters class in tr -d as you please, to control what characters can be contained in the password; the characters class presented here are all characters that are treated as a part of the word in terminal (i.e. you can double-click the word and it gets selected as a whole):
$ cat /dev/urandom | tr -d -c "a-zA-Z0-9@#%&\-\_+=:,.?/" | head -c 64; echo
uQ,XGSG4qPtE4.&UQT,jPA#=a8j-mhy+qjQUg:m#s7g1@c2-#J8D-,3zQFd+o_-W

SSH Access using pubkey's for Authentication

You can make your system's remote login way safer with just 3 simple steps:

  1. Create your public-private key pair of files.
  2. Register your public key on the server you want to access.
  3. [optional and recommended] Allow only login using the pubkey on the server.

Create public-private key pair

To generate the public-private key pair, use ssh-keygen -t rsa.

You’ll be prompted for where to save the pubkeys, then for passphrase (either empty, or 5+ letters), repeat if non-empty, and the keys get generated. Just as with passwords, it's important to use strong passphrases.

You should chmod 600 both key files, and be very careful about them.

Highly recommended is to hold them in a truecrypt partition or the like, if you carry them around. If you need to write down the passphrase somewhere, again, either use truecrypt, or use vim -x, or the likes. Don't forget, chain is only as strong as is its weakest link.

Setup the server for key-based login

Transfer the created *.pub file (typically called id_rsa.pub) to the server you want to log into remotely. Do not transfer the private part of the pair (typically called id_rsa)!!

Register the key on the server by appending it to list of authorized keys for the user this key belongs to, like this:

cat id_rsa.pub >> /home/user/.ssh/authorized_keys

The .ssh/authorized_keys file should of course also be chmod 600, and the /home/user/.ssh folder chmod 700.

Test it

Now, you should be able to login to the server using

ssh -i privatekey user@server
e.g. ssh -i ~/.ssh/id_rsa user@example.com

Server verifies your identity based on the public key, but to login you need both id_rsa and id_rsa.pub.

Fortify the server (optional, root rights required)

Once all is up and running, and you've tested the login properly, you may choose to disable password-based login.

Edit the /etc/ssh/sshd_config file (or /usr/local/etc/sshd_config on BSD’s). Add/update the following lines:

PasswordAuthentication no
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys

Then restart `ssh` – using /etc/init.d/ssh restart (or /usr/local/etc/rc.d/ssh restart on BSD’s).

You may also choose to disable root login, allowing only regular users to login, and then use sudo to become root. Simply add/update in /etc/ssh/sshd_config:

PermitRootLogin no

Using RSync together with SSH

Using password-based authentication:

$ rsync -avz -e ssh user@server:/remote/dir /this/dir/

Using pubkey-based authentication:

$ rsync -avz -e "ssh -i /path/to/id_rsa" user@server:/remote/dir /this/dir/

External Links