Saturday, June 11, 2011

What to do NOW to protect your website

 

 

Website security precautions

Sections 1-6 are absolutely necessary. They do not require a lot of technical knowledge.

1) Maintain strong security on the computer that you use to manage your website

Someone who successfully infects your PC can use it to get into your website. That is very common.
  • On any Windows PC (does not apply to Linux, Mac) that you use to administer your website, install good quality antivirus software to keep it free of viruses and Trojan downloaders that can install spyware such as keyloggers and password-stealers. Get real-time ("on access") protection that detects malware immediately when it is received. "On-demand" scanning (such as once a day or once a week) is not good enough. Malware can do all its damage, steal your data, and even delete itself, before you get around to doing a manual file scan.
     
  • On a Windows system, once a month, while logged into your PC as an Administrator, visit Windows Update to install the latest security patches for Microsoft products, including Internet Explorer.
     
  • Keep all your internet-related software such as browsers, plug-ins, and add-ons up to date with the latest security patches. Examples are Adobe Reader, Flash, and Java. You can check whether your Firefox plugins are up to date at Mozilla Plugin Check.
     
  • Use adequate security settings in your web browser. When Internet Explorer and Firefox are first installed, their default security settings are not high enough, and most people don't change them. Set JavaScript so it is Off by default and only enabled for trusted websites that require it. Follow best practices for IE, and use the NoScript add-on in Firefox. 
     
  • On a wireless network or in a public "hot spot", your data is transmitted by radio, and it is easy for someone nearby to monitor everything you send and receive that is not encrypted. Normal web browsing on http:// websites is not encrypted, and neither is a normal FTP login. Whenever you are "working wireless", use encrypted https:// to log in to your server, and use secure FTP (SFTP) to transfer files.

2) Follow accepted best practices for your website passwords

  • Use strong passwords: 8 to 20 random upper/lower/numeric/punctuation characters.
  • Use a different password in every location.
  • Only give your password to people who must have it.
  • If you give your password to someone temporarily, change it as soon as their work is finished.
Here is an entire article about why good passwords are so important. It has a strong password generator and password input boxes where you can practice typing strong passwords accurately to get used to them.

3) Choose third party scripts carefully

Don't load your website with every cool script, gadget, feature, function, and code snippet you can find on the web. Any one of them could let a hacker into your site. Before you use something new, read its vulnerability report at Secunia.com, and do a web search on it to see if people talk about it as a security hazard. Some add-ons and templates are actually designed to be malicious. Ways to avoid those are described by the Google Blogger Team in Keeping Your Blog Secure.

4) Keep third party scripts up to date

Once you have installed a script such as WordPress, SMF, Coppermine, phpBB, or any others, find a way to make sure you are notified quickly when security updates are released. Get on a mailing list, subscribe to an RSS feed, subscribe to a forum board, create a Google Alert, whatever you need to do. When a security update is released, install it within 1 day, if possible. 

5) Use good security practices for SSH

SSH, Secure SHell, gives you command line access to your server, allowing you to execute operating system commands from a remote location. Most webhosts don't allow their shared hosting customers to use SSH at all, but a few do. Resellers and those who manage dedicated servers do have SSH.
  • If you have SSH access and you use it, its password should be exceptionally strong, 16 random characters or more. I've seen servers where the log of failed login attempts was 160MB or more, and the hackers eventually succeeded because the password wasn't strong enough.
     
  • If you have SSH access and you don't use it, disable SSH so nobody can use it. There is sometimes an SSH control switch in cPanel. For reseller accounts and dedicated servers, there is a switch in WHM. If you are a reseller or run a dedicated server on which there are multiple accounts, turn SSH off for all accounts or at least those that don't use it. If you allow SSH at all, let your users ask you to enable it for them. Most never will.

6) Don't weaken your server's file and folder permissions.

Each file and folder on your server has permissions settings that determine who can read or write that file, execute that program, or enter that folder. Your webhost initially created your webspace with secure permission settings on all files and folders.
Do not modify the permissions until you know what you're doing. Don't guess. One mistake can allow any other account on your shared server to put files on your site, or allow anyone in the world to put files there by first getting into a weaker website on your shared server and running a malicious PHP script from there.
People having trouble installing web applications on their site are sometimes told to try setting the Linux permissions to 777 (for folders) or 666 (for files). Those permission levels are sometimes necessary, but they are a hazard and should only be used for folders and files for which it's absolutely necessary and only during times when it's absolutely necessary. For example, sometimes 777 only needs to be used during installation or during configuration changes or software upgrades. At other times, the application might function just fine even if you change the permissions back to more secure settings. In other words, if you need to use insecure permissions, try to minimize the amount of time they are in effect. There is no reason to leave permission levels low all the time if you only need them to be that way occasionally. Also, if software installation instructions tell you to delete the installation script itself after use, remember to do it. If it's left on the server, someone else who knows it's there (or knows it should be there) can run it, just like you can.  
A separate article has a short explanation of permissions settings.

7) Write your own scripts securely

These precautions are also absolutely necessary, but only if you write your own program code.
  • For the language you use, find and read an overview about security: PHP, ASP.NET, Cold Fusion, ...
  • When you use an unfamiliar function for the first time, check the manual for security considerations.
  • Learn to instinctively distrust data from the outside world. Write your code so that incoming malicious input can't trick it into doing something it shouldn't. Outside data includes: incoming form submission data, HTTP query strings, cookies.
  • Learn how to prevent "Remote File Inclusion". (#1 most common security error)
  • Learn how to prevent "SQL Injection". (#2 most common security error)
  • There are lots of online resources for learning how to code securely. All it takes is a web search.
  • For PHP, use a good php.ini file for extra security, to block common attacks.

8) Block suspicious activity with .htaccess

These are extra precautions that provide an additional layer of security. If you understand what this section is talking about, the discussion and code examples should help you to put some good protections in place. If you don't understand this section, don't worry about it unless you are under constant attack and other remedies have failed.
Download and examine your raw access logs, or analyze the lines here. You will most likely find attacks of the types described in my articles. Even if the attempts are unsuccessful, your logs give early warning about what methods are being used, which gives you time to figure out how to defend against them. Here are some examples of how to block suspicious activity:
  1. Ban bad robots.
    One program often misused for automated remote file inclusion attacks is called  "libwww-perl". The RFI cannot succeed if your server refuses to serve the file, so blocking this commonly malicious User-Agent is one defense. Put the following lines in your public_html/.htaccess, in a part of the file that is not delimited by HTML-style tags like <tag></tag>: 
SetEnvIfNoCase User-Agent libwww-perl block_bad_bots
# to deny more User-Agents, copy the line above and change
# only libwww-perl, to match the new name.
deny from env=block_bad_bots

SetEnvIfNoCase does a case-insensitive test of the User-Agent against a regular expression, which in this case is "contains libwww-perl". If it matches, it sets the variable block_bad_bots. The final line says if block_bad_bots was set (i.e. if the requestor matched any of the bad robots), deny the request and send a 403 Forbidden error instead. Regardless of what the bad robot was trying to do, it won't succeed.
  1. Ban suspicious URL query strings.
    Another defense against RFI is to block all requests having the form:
    GET /index.php?inc=http://badsite.com/badscript.txt?
    The following .htaccess code blocks any request where the query string (the part after the first question mark) contains "=http://" or "=ftp://". During times when you need to use a query string of that type yourself, you can comment out the code block or enable the exception shown:
# If the next line is already in your .htaccess, you don't need to add a 2nd one.
RewriteEngine On
RewriteCond %{QUERY_STRING} ^.*=(ht|f)tp\://.*$ [NC]
# Allow yourself, for SMF Forum Package Manager upgrades.
# Set it to your own IP address so you are the only one who won't be blocked.
#RewriteCond %{REMOTE_ADDR} !^111\.222\.333\.444$ [NC]
RewriteRule .* - [F,L]

To test: you should get a 403 Forbidden error when you try to go to:
http://yoursite.com?test=http://yoursite.com/anypage.htm
http://yoursite.com?test=ftp://yoursite.com/anypage.htm
If you have coded your pages so they use remote file includes from your own site or from some external site (such that your site receives requests, constructed by you, that have URLs in the query strings), my first advice is that you should try to stop doing that:
  • Instead of sending your own site a request that has a URL in the query string, you can put in the query string a text string that the receiving page translates into a URL after it receives it. That way, your script can't be tricked by someone who sends it a malicious URL instead of one of the legitimate ones it expects.
If you must send your own site requests that have URLs in the query strings, you can use a more complicated .htaccess to allow your own remote file inclusion requests but ban others:
# FIRST, DISALLOW QUERY STRINGS CONTAINING MORE INSTANCES OF http://
# THAN WE EVER USE OURSELVES, TO LIMIT THE NUMBER OF TESTS WE MUST DO LATER.
# THIS EXAMPLE ALLOWS ONLY INSTANCE PER QUERY STRING.
RewriteCond %{QUERY_STRING} (.*http(\:|%3A)(/|%2F)(/|%2F).*){2,} [NC]
RewriteRule .* - [F,L]

# NOW WE CAN TEST EACH INSTANCE AGAINST THE LIST OF SITES WE WANT TO ALLOW.
# SINCE THIS IS A NEW REWRITE RULE, WE MUST TEST AGAIN WHETHER IT CONTAINS http://
RewriteCond %{QUERY_STRING} http(\:|%3A)(/|%2F)(/|%2F) [NC]

# THEN FALL THROUGH TO THE BAN IF IT IS NOT ONE OF THE SITES IN OUR ALLOW LIST.
RewriteCond %{QUERY_STRING} !(http(\:|%3A)(/|%2F)(/|%2F)(www\.)?site1\.com) [NC]
RewriteCond %{QUERY_STRING} !(http(\:|%3A)(/|%2F)(/|%2F)(www\.)?site2\.com) [NC]
#ADD A LINE FOR EACH EXTERNAL SITE YOU WANT TO ALLOW TO APPEAR IN QUERY STRINGS.

RewriteRule .* - [F,L]

Allowing for more than one instance of http:// in your query strings is possible. It requires complex code that we can custom design for you if needed.
Other query string bans:
1) Malicious RFI attempts almost always have a question mark at the end of the query string. Ban any query string that contains a question mark. The first question mark (which marks the beginning of the query string) is not part of the query string, so only question marks after the first one will trigger the ban:
RewriteCond %{QUERY_STRING} (\?|%3F) [NC]
RewriteRule .* - [F,L]

2) Be creative: find other characteristics that are common in the attacks on your site but that are never present in legitimate requests. Be thorough: use every good ban rule you can think of. It is very satisfying to see an attack on your site and know that even though it only needed to trigger one ban rule to fail, there were six others in reserve that it would have triggered.
  1. Ban IP addresses responsible for suspicious activity.
    You can block IP addresses (or ranges) in .htaccess or by cPanel > Deny IP. Although such bans can be useful against IP addresses you are 100% certain will never make a legitimate request, they aren't otherwise very practical. Once a botnet starts attacking your site, the requests will come from hundreds of different IPs, and banning them all will be futile. It is much better to ban by the other characteristics of the requests.
     
See this forum thread for further discussion about using .htaccess to block malicious requests, links to websites with suggested .htaccess code for blocking such requests, and a basic introduction to help understand the Perl regular expressions that are used for pattern matching in .htaccess.

Preparations that will make hack diagnosis and cleanup easier

1) Always have a backup copy of your entire website and its databases

You can use FTP and/or cPanel > Backups. Keep the backup somewhere not on your server, such as on your local PC or a DVD. Even if your webhost does backups, make a separate set for yourself. Do a new backup whenever there is enough new content that you don't want to have to redo the work. Keep more than one "generation" of backups. For example, if you backup monthly, keep separate versions from 1 month ago and from 2 months ago. This guards against backing up your site after it's been infected but before you discovered it. You'll still have (hopefully) a slightly older backup that isn't infected. For the same reason, don't backup too often.

2) Turn on log archiving in cPanel now

Your raw HTTP and FTP logs are an important source of information after an attack, but the logs are normally deleted each day. Enable archiving to allow them to accumulate and preserve the evidence after an attack. Periodically download and review the logs to see what kinds of attacks are being launched against your site. As is so often the case, becoming familiar with what is normal will help you detect when something is not. Accumulated logs can take a lot of disk space, so you might want to delete old ones from the server periodically.

3) Get a complete list of your site files NOW while they are known-good

This article describes how to get a list of all the files in your website. If you do it now, it will be a baseline list of the files you can assume are supposed to be there. If your site gets damaged, the list will help you decide whether a file you don't recognize is new or is just a system file that you never noticed before.

4) Explore your website and become familiar with what is there

Not just your pages, but the whole site, using FTP or File Manager or the complete file list you made. If you get used to what is normal, things that aren't will catch your attention.

5) Use good database connection practices in scripts:

a) Create separate MySQL users for your scripts to use

If you use your cPanel userID and password for database connections in your scripts, then changing your cPanel password will instantly break all your scripts until you recode them to use the new password.
Instead, create one or more new users, completely unrelated to your cPanel login, that your scripts can use for their database connections:
  1. Go to cPanel > MySQL® Databases > Current Users.
  2. In Username: enter the name of the user to create. Although the existing user names might appear as YourUserID_username, don't enter the prefix and underscore. cPanel will do that for you, if needed.
  3. In Password: enter the password to use. Make it a strong one.
  4. Click Create User, read the confirmation screen, and then Go Back to the MySQL Account Maintenance page.
  5. Go to the Add Users To Your Databases section.
  6. In the left dropdown box, select the user you just created.
  7. In the right dropdown box, select the database you want that user to be able to connect to.
  8. Select the Privileges you want that user to have for that database, by checking the appropriate boxes. Select only the privileges the user really needs for performing whatever tasks your scripts will do. Granting only limited privileges is a security precaution.
  9. Click Add User To Database. Your new user now has the specified privileges, for that database only. Add the user to other databases, if needed.
Now update your scripts so they use the connection data for this new user instead of your old cPanel user. However, ...

b) Put your MySQL connection data in a well protected file

If each of your scripts has its own code block for database connection, then if you are hacked and have to change your passwords, you'll have to hunt through all your files to find every code block that needs changing.
Instead, put all your database connection code in one central location such as an include file that is well-protected from web access, and make all your scripts read it from there. There are examples and some discussion about how to do this in the User Contributed Notes at http://us.php.net/mysql_connect. You can protect your include file by putting it in a folder above public_html, or in any folder that is closed to web access by an .htaccess file, or by the other methods mentioned in the php.net Notes.
Unfortunately, none of these protection methods will keep your data safe from someone who has actually gotten into your site, but the new database connection method you have just created will make it easy to change your password (in just one place) if that does happen.

0 comments:

Post a Comment