Tagged with "php" http://www.addedbytes.com/feeds/tag-feed/ en Web Development in Brighton - Added Bytes 2006 120 Open Source PHP E-Commerce Platforms Compared http://www.addedbytes.com/blog/open-source-php-e-commerce-platforms/ Contents
  1. The Contenders
  2. Installation
  3. Theming
  4. Extensibility
  5. Development
  6. Support
  7. Hosting and Performance
  8. Management
  9. CMS
  10. Security
  11. Consumers
  12. Comparison Table
  13. Winners and Losers
  14. Honourable Mentions
  15. TL;DR

The Contenders

Magento LogoThe first name down was the big dog in this particular park - Magento. In a relatively short space of time, it has achieved remarkable success, and its recent acquisition by eBay indicates little intent to slow down.

OpenCart LogoSecond, showing great promise, is the wonderful OpenCart. OpenCart is known for being a speedy way to get an e-Commerce site online and for having an easy-to-work-with codebase. Not as full-featured or "entreprisey" as Magento, it is nevertheless an excellent platform.

PrestaShop LogoUsually mentioned in the same breath as OpenCart as a worthy alternative to Magento, PrestaShop is a capable platform using the Smarty templating engine. The most common complaint? It's developerd primarily by a company in Paris, so unless your French is up to speed you may find the documentation a touch tricky.

Drupal LogoThe only entry in the list which isn't a specialist e-Commerce platform, Drupal is still an extremely popular choice, largely because of its large community and vast array of extensions. It has strengths in areas where the other contenders are lacking, primarily due to its primary function being as a CMS rather than an e-Commerce system. The Commerce plugin (as one of several options) adds e-Commerce functionality to the system.

osCommerce LogoAnd finally, bringing up the rear, is the oldest of the lot - osCommerce. Despite a history of poor security, difficult maintenance and spaghetti code, it remains one of the most used platforms and has a huge community behind it. Development has slowed recently, prompting rumours that the project may be heading for the graveyard.

With the exception of Drupal, where an extension is required to add basic e-Commerce functionality, this comparison will not include functionality added through extensions - I am comparing the products out of the box.

Installation

Magento was simple to download, with older versions of the software available in tabs, although, system requirements were hidden away on the downloads page. Installation instructions were provided during the download process, and the installation guide was excellent. Installation was slow, though, largely because of the size of the software. It could have done with more explanatory text - osCommerce did this well - and any cleanup was handled automatically, which was excellent.

OpenCart has a reassuringly professional feel to its installation procedure. Downloads were easy to find, including earlier versions, although no installation guidance was provided when downloading. Requirements checking was simple and clear, and your stage in the process well indicated. It also lacked explanatory text and there was no option to clean up automatically after itself and set sensible permissions.

PrestaShop downloads were easy to find and grab, though system requirements were rather better hidden, with a link near the bottom of the download page. The download screen links to installation guides on the main PrestaShop site, which are excellent and include videos - but these are not linked to from the installation procedure, which is a real shame. System requirements checking was simple enough, with clear instruction on what to do to correct any issues. Cleanup is not automated, but is enforced (good idea) - you can't log in until you've renamed your administration folder and deleted the install folder. Finally, each of the two installations run during the writing of this article resulted in errors in either the admin area or the shop itself.

Drupal downloads were easy enough to find, and installation instructions and system requirements were both linked obviously from the downloads page. Indications of where you are in the installation process are simple, and requirements checking during the process was good, with clear instructions on how to address any issues. Unfortunately, it is the only of the systems to require you to manually create a configuration file, and this seemed rather unnecessary. As with most of the other platforms, there was little help text along the way. Drupal did clean up after itself though, with the installer being disabled after it has been run.

osCommerce was less smooth than the others to download - it's not obvious where to go to download the software from the homepage, although the downloads page is very simple. Requirements were specified on the download page, but no installation instructions. It was simple to install, with a guided process that confirmed requirements were met, gave good feedback and included plenty of help text. It might have been nice if it had given the option to run a cleanup script once complete, to wipe the install directory and set sensible permissions.

Theming

Magento has an excellent theming engine, with the ability to inherit elements from one theme to another, making theme variants easy and quick to produce. The sheer volume of folders and nesting can be daunting to someone new to the platform. There are some excellent themes to download as well, which can often provide a good starting point. Unfortunately, Magento is also extremely heavy, loading large amounts of CSS and JavaScript by default. Themes often end up being extremely large, making ongoing management sometimes more painful than with other systems.

OpenCart uses PHP files for its templates, which is something I am a fan of (why introduce a new variable and control syntax, processed by PHP, when it already has these things?) and as a result the templates are simple to write and maintain. Themes are held in folders, so many can be installed to a site at once. There are plenty of themes available as well, both free and paid.

PrestaShop makes use of the well-known Smarty templating engine, and can handle multiple templates being installed at one time. The themes don't have the ability, like Magento, to inherit elements from each other, but they are easy to build and simple to maintain. There are plenty of themes available as well, both free and paid.

Theming Drupal is not considered terribly good fun. Designers and front end coders working with it for the first time have a distinctive haunted look, largely because the parts of each page can come from so many different places. On the plus side, multiple templates can exist side by side, and templates can include extra functionality when needed. There are also some excellent templates available to download, although most will require some work to make them fit the specifics of your site, depending upon the modules you have installed.

The default osCommerce theme is terribly outdated and a major let down. As with the other platforms, though, there are some stunning templates available. Unfortunately, there is no integrated templating engine, and as a result many templates require changing of core files for installation.

Extensibility

All of the contenders score well on extensibility, with both the type, range and ease of building of extentions (a.k.a. addons) taken into account. Drupal and Magento are pretty even - Drupal has a much larger collection of extensions, largely because they are quicker and cheaper to build, but Magento's are generally of a higher quality.

The rest are all fairly evenly matched, with extensions numbering in the thousands providing similar added functionality to all of the platforms. OpenCart has a slight edge over PrestaShop and osCommerce when it comes to extensions development though, thanks to better documentation than PrestaShop and better architecture than osCommerce.

The most commonly required extensions - for payment and shipping configuration - are all present on all platforms for most of the large providers.

Development

Most stores require at least some ongoing development, integrating with new services and adding new features over time. So how do these platforms compare when it comes to having some custom work done?

It is difficult to know how to score Magento when it comes to development. The system's architecture, inheritance setup, XML config system and use of the MVC pattern all make it usually excellent to work with. It provides plenty of API interfaces, reusable objects, and has intelligent use of namespacing to reduce the risk of conflicts between modules. The code is also clean and well documented throughout. On the other hand, it can be slow to write for - it is a monster, with hundreds of files in a nested structure that really takes some getting used to. The observer pattern used frequently in Magento can make debugging some problems deeply painful, as you need to find which of dozens of observers are causing a headache. Overall, it is the most technically advanced, and by some way, but that carries with it something of an overhead, making development for Magento often more expensive than comparable systems.

OpenCart is, for the most part, pretty simple to develop for. It's generally faster than Magento, thanks to a simpler structure and faster page times. It uses an MVC pattern, and has great documentation. It does suffer from an unfortunate folder structure, where a single simple custom module can have files in lots of different parts of the directory tree, but once you are familiar with the layout this is less of an issue. There is a lot of repetition in creating OpenCart modules as well - Magento's easy Grid/Edit/Form setup is much simpler and faster. Overriding core functionality is also a painful experience, relying on third party modules that search and replace within code, rather than hooks or class overrides. Despite these shortcomings, generally OpenCart's simplicity makes developing modules more of a pleasure than with some of the competition.

PrestaShop has a better module folder structure than OpenCart, similar to Magento's way of doing things, with every module in its own distinct folder. The development documentation has not been great in the past, though does seem to be improving. PrestaShop also provides a robust system for overriding core functionality as well as a variety of hooks and an API.

Drupal uses a simple and straightforward module system for development, meaning modules can often be added extremely quickly, each within its own folder. If the recommended development practices are followed, it's easy enough to avoid conflicts between modules. Where Drupal can be trickier is in overriding core functionality. Often the only way to do so is to copy a core module, alter it, and make the same changes whenever updating in future (this is not dissimilar to other platforms, of course). Drupal does separate themes from modules well, but does not go quite as far as an MVC pattern. Drupal uses a system of hooks to enable you to tap into or override normal functionality in your own modules, however this becomes problematic when wanting to modify or interact with third party modules, as these may not implement hooks in the same way, if at all.

osCommerce is extremely poor when it comes to development. Almost all development work involves modifying core files, and those are largely procedural code. There is no universal URL handler to tap into, no module system, no hooks. This does mean it is often extremely quick to make small changes to the site. It also means those changes can have far-reaching effects, upgrades are extremely painful, and security issues are easy to introduce.

Support

Drupal is well in the lead here, with extensive and varied support communities. They have forums, their own Stack Exchange site (in addition to a healthy amount of activity on the main Stack Overflow), and each module has its own mini-support system complete with bug tracking. All of which is lucky, because with Drupal you can spend a lot of time looking for help.

Magento is just a little behind Drupal. There is an active community on the main Stack Overflow site, and Magento have their own forums - although a large number of posts there seem to go unanswered. Magento also offer paid support options.

OpenCart, PrestaShop and osCommerce all score roughly evenly here. All have their own active forums (OpenCart, PrestaShop, osCommerce), and all have small communities on Stack Overflow (OpenCart, PrestaShop, osCommerce). PrestaShop offer a variety of paid support options as well.

Hosting and Performance

With Open Source systems a couple of the potential major costs usually associated with ecommece businesses are no longer an issue - building a system is unnecessary, and no need to pay for a license. However, there are still significant costs associated with hosting to be considered. Performance is a significant issue too, with slow sites converting customers at a lower rate than faster competitors.

Magento scores poorly here, requiring a beefier server than the other contenders to serve a comparable level of traffic, as well as needing PHP modules that are not always present on web servers by default. Performance can be very poor without tweaking of server configurations and addition of opcode caching modules. Even with plenty of server-side shenanigans, pages are heavy and difficult to trim to a healthy size. It redeems itself slightly with its ability to scale to multiple servers easily, but, for smaller online shops, this is an area where Magento has much room for improvement.

OpenCart and PrestaShop are evenly matched, with comparable load times out of the box and similar hosting requirements. They are not as demanding or as expensive to host as Magento, and both will work on the majority of PHP hosts.

Drupal will run on most PHP hosts, but will usually be pushing the limits of standard virtual hosts. It runs well on VPSes and up, but also suffers from slow load times. As with the other sites, speed can be vastly improved with opcode caching and some of the community modules.

osCommerce is not terribly fast when it comes to page loads out of the box, though there are plenty of optimisations you can perform to bring it up to spec. Where it does score well, however, it ubiquity of hosting. It has been around since early version of PHP and runs fine on a standard virtual server, so can be one of the cheapest and easiest system to host.

Management

Management of a store, including product pricing, inventory and data, categorisation, order statuses and so on is important to any e-Commerce venture. A management system should be intuitive and quick enough that customer service staff can use it without extensive training, and should allow restriction of access to different parts of the system for different users. Functionality like the ability to manage multiple stores from a single interface, handle multiple languages, or customise designs for specific pages or sections, while not universally required, is becoming more and more important.

Magento scores well in most ways, although their management area is not particularly intuitive (especially when it comes to order statuses, invoicing and shipping). Access control is excellent, and the system allows almost every aspect of products to be controlled through their EAV model. Products can be of various types (attribute sets and configurable products both work very well), special offers are powerful (although no 3 for 2 support is still a serious omission), and rule-based product relationships are very useful. Magento also offers multi-website and multi-store functionality, although this can have a significant negative effect on performance.

OpenCart is more intuitive than Magento, handles multiple stores well, and has a basic but functional permissions management system. Editing of products, categories and orders is simple and quick. Especially nice is its support of multiple languages. However, special offer support is weak, automated relating of products is missing, and stock control for configurable products is limited to one criteria (so if you sell tshirts, you can't specify stock for each combination of colour and size you have available).

PrestaShop supports configurable products well and has good granular permissions management. Unfortunately, it is not particularly intuitive, and does not support multiple stores from a single installation (although this feature is currently in testing, so should be available soon). Unfortunately, like OpenCart, it also has weak special offer management facilities and no support for automated relating of products. I do like that management of an item, that on other systems is spread over several pages, is often on one page in PrestaShop - a small point, but much appreciated.

Drupal scores badly here, largely as a result of e-Commerce being an addon, rather than native functionality. As a result, categories, products and related products are traumatic to set up. Access control and multiple store support are both good, but the kinds of refinements expected of a modern e-Commerce platform are lacking - most things are possible, but slow and usually in a way that makes introduction of errors almost inevitable. Finally, and possibly most seriously, it is badly let down by its counter-intuitive administration area.

osCommerce is simple to use, though not intuitive. Unfortunately, that is largely where the positives end - it cannot support multiple stores, configurable products, related products or users with different levels of permissions. Many of these features are available by way of community modules, however. It does have basic support for special offers, and a simple to manage system for categories.

CMS

This is an area where Drupal shines, and where Magento, OpenCart, PrestaShop and osCommerce are well behind the curve. A modern CMS allows granular control of access to edit content, versioning of documents, publishing dates, commenting on posts and so on. At the minimum, an e-Commerce platform should be able to offer basic blog functionality. Only Drupal is up to the task here, being first and foremost a CMS.

Security

Only osCommerce presents a serious concern out of the box, with a terrible reputation for, and history of, insecurity. Efforts to improve it are ongoing, but once a product has a reputation for poor security it is tough to change it.

Drupal fares a bit better, although the reliance on modules means that sometimes, even though the main platform itself might be secure, exploitable weaknesses are introduced (this is true of all of the platforms to some extent, but Drupal has greater reliance on extensions if run as an e-Commerce platform). Generally security of the Drupal platform has been good, and it's been well tested, running high profile sites like Whitehouse.gov without incident.

Magento, OpenCart and PrestaShop are all fairly even here. Exploits of the core platforms are comparable in number and severity. Magento offers an Enterprise version of their software (for a fee) and this claims to be fully PCI compliant - if this were to be brought to the Community edition as well, it would have an advantage in future.

Consumers

Finally, how easy is each for a consumer to use, and how good is each platform at bringing in customers and marketing specific products? This is almost entirely dependant upon the theme chosen, the quality of development and hosting, and a thousand other factors. However, out of the box, ...

Magento is excellent for consumers, despite a few recurring issues. Filterable categories are excellent, and Magento handles complex products extremely well, making the shopping process very straightforward. Integrations with third parties for payments are also mature and well tested, meaning few surprises for shoppers. Sometimes let down by bizarre behaviour (categories showing as empty and the search returning no results being common issues), it is still comfortably ahead of the competition. Search engine optimisation is excellent, and the ability to run promotions from the CMS at various points in the site is also very welcome.

OpenCart, PrestaShop and osCommerce are very evenly matched here. All provide a friendly browsing experience, and both suffer from the serious ommision of category filters; however all also have an excellent shopping and checkout processes. OpenCart and PrestaShop both include product comparison, while of the three only OpenCart includes wishlist functionality. OpenCart and PrestaShop have excellent SEO capabilities, and both provide support for promotions on the site.

With a little patience, Drupal is capable of providing a simple and easy to use shopping experience. It lacks some of the options and more advanced refinements of the dedicated e-Commerce offerings, but with Drupal anything is possible - given enough time. It also has good SEO support and the ability to run promotions through the site.

Comparison Table

Magento OpenCart Prestashop Drupal osCommerce
/10 Installation 8 7 7 7 7
/10 Theming 7 8 7 5 3
/10 Extensibility 8 7 6 8 6
/10 Development 8 7 8 6 2
/10 Support 6 5 6 8 5
/10 Hosting 4 6 6 5 7
/10 Management 9 7 6 3 2
/10 CMS 4 3 3 8 2
/10 Security 8 8 8 7 4
/10 Consumers 8 7 6 5 5
/100 Totals 70 65 63 62 43

Winners and Losers

Magento, despite extremely rapid growth, easy installation and excellent extensions, is let down by a lacklustre CMS, expensive running and development costs, and a comparatively poor (unless you are prepared to pay) support setup. Third party extensions and community sites exist to cover most of these shortfalls though, and the quality of code and the power available to extensions make this a great choice for serious e-Commerce businesses.

If you're looking to keep your development costs down, both OpenCart and PrestaShop are fine choices, though for me OpenCart seems to have the edge at the moment. Both have a bit of a way to go to catch Magento, though, especially when it comes to addons and sales features.

If you're after content bells and whistles, you're going to find it tough to talk yourself out of Drupal. It isn't the easiest system to develop with, but there's not much out there that can compete with it on power.

osCommerce is, at the moment, just not competitive, and has not kept pace with the comparable alternatives. Best avoided, for now.

Honourable Mentions

Other Languages

You'll have noticed by now that the above are all PHP/MySQL-based platforms. There are plenty of languages out there and there are open source e-Commerce platforms available on almost all of them. If you're more comfortable with another language than PHP ... then very sorry, but you've been reading the wrong list.

MODX

Personally, my favourite CMS for content sites is MODX - it's easy to use, simple to develop for, and has a great community. Unfortunately, e-commerce support is weak, with most solutions available being third party integrations (e.g., FoxyCart) rather than native e-commerce. However, talk of new e-commerce options is rife, and I'm hopeful something will come along to fill this gap soon.

Wordpress

Much like MODX, Wordpress does not have native e-commerce functionality. However, again as with MODX, Wordpress has plenty of plugins that can add a store to a blog, such as WP e-Commerce. There's still a long way to go until either Wordpress or MODX is competitive when it comes to e-commerce, but the signs for both are encouraging.

Zen Cart

It was a tough choice whether to pick Zen Cart or osCommerce for the fifth contender in this rundown. When I revisit this later on, most likely it will be Zen Cart that makes the cut. osCommerce I chose for this first comparison because of its age and because of its prevalence - it is still widely used, even if well behind more modern options.

TL;DR

Drupal if you need a decent CMS. Otherwise, in order: Magento, OpenCart, PrestaShop, osCommerce.



]]>
Wed, 29 Aug 2012 13:17:00 +0100 http://www.addedbytes.com/blog/open-source-php-e-commerce-platforms/ Dave Child ,,,,,,,,,
If PHP Were British http://www.addedbytes.com/blog/if-php-were-british/ When Rasmus Lerdorf first put PHP together, he - quite sensibly, despite his heritage - chose not to write it in Greenlandic or Danish. Good job too - that would have been rather unpleasant to work with.

When Rasmus Lerdorf first put PHP together, he - quite sensibly, despite his heritage - chose not to write it in Greenlandic or Danish. Good job too - that would have been rather unpleasant to work with. He opted instead, being in Canada, for a more local tongue. No, not French. Not Canadian English either. No, he went for that bastard dialect of the Queen's English commonly referred to as "US English".

PHP developers in Britain have been grumpy about this ever since. What was he thinking? And more importantly, how do we undo this travesty? How do we developers ensure the traditions of the British Empire continue to be upheld, even in the digital age?

A Slap in the Face

$variable_name

The first, but maybe the most important, of many changes that will allow PHP to achieve a more elegant feel is to remove that symbol so beloved by the US and replace it with something altogether more refined. More solid. More ... sterling.

£variable_name

Getting Started

<?php
    echo 'Hello World!';
?>

How many of today's British programmers have been put off at the outset by the brazen informality of this simple yet obscenely Americanised program, colloquially referred to as "Hello World"? A more Imperial, formal introduction might encourage a greater proportion of young British talent to remain with the language and thus give the broader community a more urbane air.

<?php
    announce 'Good morrow, fellow subjects of the Crown.';
?>

Abbreviations

Few things are more abhorrent to the British than unnecessary abbreviations. "Text speak" is unheard of on the streets of London, as the natural ingrained British grammarian simply refuses to stoop to sending messages of the "c u soon traffic kthxbye" variety, instead proferring something altogether more elegant: "Dear Sir/Madam. I will arrive as soon as time allows, which I expect to be within the hour. I assure you the horses shall not be spared. Yours respectfully." (slower to type, yes, but we do not like to be rushed).

PHP, on the other hand, is full to bursting with abbreviations and acronyms which are entirely unnecessary:

str_replace()
is_int()
var_dump()
preg_match()
json_encode()
mysql_connect()

The following changes should improve things:

string_replace()
is_integer()
variable_dump()
perl_regular_expression_match()
javascript_object_notation_encode()
my_structured_query_language_connect()

Edit: I have corrected the expansion of "preg_match" - thanks to those who pointed it out.

Eloquence

if ($condition) {
    // Code here
} else {
    // Code here
}

Shakespeare would be ashamed to see his native tongue twisted into this monstrosity. Brevity is to be applauded in the right context - in some dark corner, where it shall be seldom seen - but not here. The if ... else block is the most used conditional code in all of PHP, so it must be made as inoffensive as possible. There are many options for its replacement, but this may be the strongest:

perchance (£condition) {
    // Code here
} otherwise {
    // Code here
}

The same naturally applies to the Americanised switch ... case construct, which one can only describe as clunky and unpleasant:

switch ($variable) {
    case $option1:
        //Code here
        break;
    case $option2:
        //Code here
        break;
    default:
        //Code here
        break;
}

Words such as "switch", "break" and "default" are hard on the reader and lack context. The Right Honourable biggerthancheeses was kind enough to contribute a more gentrified suggestion (and has some interesting ideas, particularly around replacement of "include()" with something like "i_might_be_partial_to()", demonstrating a natural talent for the Imperialisation of programming languages):

what_about (£variable) {
    perhaps £possibility:
        //Code here
        splendid;
    perhaps £other_possibility:
        //Code here
        splendid;
    on_the_off_chance:
        //Code here
        splendid;
}

Spelling

imagecolorallocate()
serialize()
newt_centered_window()
connection_status()

Words fail me at this point. How is any self-respecting gentleman expected to make head or tail of these "words". It beggars belief that anyone could allow such distortions of words to be entered into a programming language. They, along with the cornucopia of similar errors, should be reverted to their proper forms immediately:

imagecolourallocate()
serialise()
newt_centred_window()
connexion_status()1

Manners

try {
    // Code here
} catch (Exception $e) {
    // Handle exception
    die('Message');
}

The try ... catch block is an excellent example of PHP's lack of manners. Far too direct to be allowed in the new PHP. Additionally, the word "die" is so very depressing. This new block, although more verbose, is vastly more polite and upbeat:

would_you_mind {
    // Code here
} actually_i_do_mind (Exception £e) {
    // Politely move on
    cheerio('Message');
}

Class

Perhaps nothing is as important and ingrained in the British psyche as the notion of class and, while there are few opportunities for change within this part of PHP, the changes that there are to be made here are important.

class Republic {
    public $a;
    private $b;
    protected $c;
}
$example = new Republic();

To begin with, the current system has no place for class hierarchy and this is unacceptable. So we shall begin by giving classes specific levels - upper, middle, working - and no class can access the methods of one of a higher level without the explicit permission of the higher order class (of course, though it might then have access, it would not be a true member of the higher order and could not itself grant higher order access to other lower order classes). "Public" and "Private", in the British class system, are often synonymous (see, for example, school system nomenclature), so these must be adjusted, as should the "Protected" property visibility. The word "new", while passable, has a much more appropriate replacement in matters of class.

upper_class Empire {
    state £a;
    private £b;
    hereditary £c;
}
£example = nouveau Empire();

The Sun Never Sets ...

It is hoped that these few simple changes will improve the reputation and status of PHP among other languages. No longer will it be the poor American cousin - instead it can take its rightful place as the - British - King of the scripting languages.

Thanks

Many thanks to Mark and Pat, former colleagues, who helped start this resurrection of the British Empire in the pub on Friday.

1. Yes, connexion.



]]>
Sat, 20 Aug 2011 07:28:21 +0100 http://www.addedbytes.com/blog/if-php-were-british/ Dave Child ,,,
Writing Secure PHP, Part 4 http://www.addedbytes.com/articles/writing-secure-php/writing-secure-php-4/ Writing Secure PHP series, covering cross-site scripting, cross-site request forgery and character encoding security issues.

In Writing Secure PHP, Writing Secure PHP, Part 2 and Writing Secure PHP, Part 3 I covered many of the common mistakes PHP developers make, and how to avoid some potential security problems. This article covers some of the more advanced security problems common to PHP on the web.

Cross-Site Scripting (XSS)

Cross-site scripting (often abbreviated to XSS) is a form of injection, where an attacker finds a way to have the target site display code they control. In its most basic form, this can be as simple as a site that allows HTML characters in usernames, where someone can specify a username like:

DaveChild<script type="text/javascript" src="http://www.example.com/my_script.js"></script>

Now, whenever someone sees my username on the target site, the script I've added to my username will run. I could potentially use this to grab the person's login information, log their keystrokes - any number of nefarious activities.

As a developer, you can combat this type of attack by encoding or removing HTML characters (watch out for character encoding issues, as outlined next). Even better than stripping out unwanted characters is to allow a whitelist of safe characters in usernames and other fields. Be especially careful with e-commerce sites where you are listing orders in a CMS - an XSS vulnerability may allow an attacker to gain administrative access to your CMS. It is also important to turn off TRACE and TRACK support on the server, as if there is a vulnerability (and always assume that despite your best efforts there will be) these potentially allow an attacker to steal a user's cookie.

As a user you are also vulnerable to this sort of attack, and it is very difficult, at the moment, to make yourself safe against it. Vigilance is key, and to that end I have released a userscript that warns you about third party scripts (for users of GreaseMonkey, Opera or Chrome).

Cross-Site Request Forgery (CSRF)

Despite the similar name, CSRF is unconnected to XSS. CSRF is a form of attack where an authenticated user performs an action on a site without knowing it.

Let's assume that Jack is logged in to his bank, and has a cookie stored on his computer. Each time he sends an HTTP request to the bank (i.e., views a page or an image on a page) his browser sends the cookie along with the request so that the bank knows that it's him making the request.

Jill, meanwhile, runs a different website and has managed to get Jack to visit it. One of the items on the page is in fact loaded from the bank, for example in an iframe. The URL of the iframe or request contains instructions to the bank to transfer money from Jack's account to Jill's. Because the request is coming from Jack's computer, and includes his cookie, the bank assumes it is a legitimate request and the money is transferred.

This type of attack is extremely dangerous and virtually untracable. As a developer, your job is to protect against it, and the best way to do that is to remember Rule Number One: Never, Ever Trust Your Users. No matter how authenticated they are, do not assume every request was intended.

In practical PHP terms, you can combat CSRF with several relatively simple coding habits. Never let the user do anything with a GET request - always use POST. Confirm actions before performing them with a confirmation dialog on a separate page - and make sure both the original action button or link and the confirmation were clicked. Even better, have the user enter information like letters from their password on the confirmation page.

Add a randomly generated token to forms and verify its presence when a request is made. Use frame-breaking JavaScript. Time-out sessions with a short timespan (think minutes, not hours). Encourage the user to log out when they've finished. Check the HTTP_REFERER header (it can be hidden, but is still worth checking as if it is a different domain to that expected it is definitely a CSRF request).

Character Encoding

Character encoding in PHP and associated database systems is worthy of its own series. In any one request, there may be more different character encodings in use than you might think.

For example, a single request and response (uploading a file to a server and writing information to a database) may involve all of the following differently items with different character encodings: the HTTP request headers, post data, PHP's default encoding, the PHP MySQL module, MySQL's default set, the set of each table being used, a file being opened and read, a new file being created and written, the response headers and the response body.

English-speaking developers generally don't have much cause to get embroiled in character encoding issues, and that results in a lot of developers with a serious lack of understanding of how character encodings work and fit together. For those that do have a reason to look at character encodings, usually that interest ends with the setting of the response's character set.

However, character sets are a fundamental part of all web development. English alone can exist in any one of a wide variety of sets, and developers are usually familiar with the most common two: ISO-8859-1 and UTF-8. Fewer are familiar with UCS-2, UTF-16 or windows-1252. Still fewer are familiar with commonly used alternative language sets (e.g, GB2312 for Chinese).

Which, in a very roundabout way, brings me on to the security pitfalls of character encodings. Where data is processed by PHP using one character set, but a database server uses a different character set, a character (or series of characters) deemed safe by PHP may in fact allow SQL injection against the database.

PHP security expert Chris Shiflett has written about this issue and included an example of how it can be exploited to allow SQL injection even where input is sanitized using addslashes().

The solution is to always always use mysql_real_escape_string() rather than addslashes() (or use prepared statements / stored procedures), and to explicitly state character sets at all stages of interaction. Ideally, use the same character set throughout your system (UTF-8 is recommended) and where PHP allows you to specify a character encoding for a function (e.g., htmlspecialchars() or htmlentities()), make use of it.

It's not just SQL that's vulnerable as a result of character encoding bugs. Cross-site scripting is possible even where HTML characters are escaped if character sets are not handled properly. Fortunately, once again that is simple to avoid by properly setting character encodings at all stages of the process and specifying character encoding for functions where possible.



]]>
Thu, 11 Sep 2008 13:11:14 +0100 http://www.addedbytes.com/articles/writing-secure-php/writing-secure-php-4/ Dave Child ,,,,,,,,,,,
PHP Querystring Functions http://www.addedbytes.com/blog/code/php-querystring-functions/ Adding and removing variables to and from URLs using PHP can be a relatively simple process admittedly, but I have a couple of functions I use often to make the process even less time-consuming.



Add Querystring Variable



A PHP function that will add the querystring variable $key with a value $value to $ur

Adding and removing variables to and from URLs using PHP can be a relatively simple process admittedly, but I have a couple of functions I use often to make the process even less time-consuming.

Add Querystring Variable

A PHP function that will add the querystring variable $key with a value $value to $url. If $key is already specified within $url, it will replace it.

function add_querystring_var($url, $key, $value) {
    $url = preg_replace('/(.*)(?|&)' . $key . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
    $url = substr($url, 0, -1);
    if (strpos($url, '?') === false) {
        return ($url . '?' . $key . '=' . $value);
    } else {
        return ($url . '&' . $key . '=' . $value);
    }
}

Remove Querystring Variable

A PHP function that will remove the variable $key and its value from the given $url.

function remove_querystring_var($url, $key) {
    $url = preg_replace('/(.*)(?|&)' . $key . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
    $url = substr($url, 0, -1);
    return ($url);
}


]]>
Tue, 05 Dec 2006 15:41:30 +0000 http://www.addedbytes.com/blog/code/php-querystring-functions/ Dave Child ,,,,,,,,,,
RSS to iCal http://www.addedbytes.com/blog/rss-to-ical/ I have been looking for a way to convert the BBC weather feed for my area to iCal, so I can subscribe to it. It's date-based, after all, and RSS never seemed to me to be an appropriate format for subscribing to weather information. iCal always struck me as being "better" for that purpose.

I have been looking for a way to convert the BBC weather feed for my area to iCal, so I can subscribe to it. It's date-based, after all, and RSS never seemed to me to be an appropriate format for subscribing to weather information. iCal always struck me as being "better" for that purpose. Of course, the BBC only have an RSS feed for local weather. What I needed was a converter.

After some hunting, I discovered that Dean Sanvitale had written a PHP script to convert RSS feeds to iCal format. However, his site (codent.com) appears to be long since abandoned and the script is no longer available from there. Fortunately, the Wayback Machine did have a copy. Dean originally released the script under a Creative Commons License which, fortunately, allows me to make the script available to download from this site (note: the script is available from this site under the same license).

So, if you're looking for a way to convert an RSS feed to iCal, this PHP script will do the job. Thanks Dean!

Source: rss2ical.txt



]]>
Thu, 19 Oct 2006 12:14:16 +0100 http://www.addedbytes.com/blog/rss-to-ical/ Dave Child ,,,,,,,,,,
"Select All" JavaScript for Forms Posting to an Array http://www.addedbytes.com/blog/code/select-all-javascript-for-forms-posting-to-an-array/ The problem that led to this snippet of code was that when posting from a form to a PHP script, you may sometimes want to have several fields with the same name and different values. For example, you might want people to be able to tick boxes to indicate which cities they have been to from a list.

The problem that led to this snippet of code was that when posting from a form to a PHP script, you may sometimes want to have several fields with the same name and different values. For example, you might want people to be able to tick boxes to indicate which cities they have been to from a list. You would normally add "[]" to the name of the field inputs, like so:

<input type="checkbox" name="cities[]" value="London"> London
<input type="checkbox" name="cities[]" value="Paris"> Paris
<input type="checkbox" name="cities[]" value="Berlin"> Berlin
<input type="checkbox" name="cities[]" value="Madrid"> Madrid
<input type="checkbox" name="cities[]" value="Rome"> Rome

When the form is received by PHP, whichever items are ticked in the cities list above are accessible in the array $_POST['cities']. This is very handy.

Unfortunately, the addition of square brackets causes trouble with JavaScript, especially with a "Select All" function - which allows you to check all boxes at once by clicking a single one. This script works around that using regular expressions.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Checkbox Fun</title>
<script type="text/javascript"><!--
 
var formblock;
var forminputs;
 
function prepare() {
  formblock= document.getElementById('form_id');
  forminputs = formblock.getElementsByTagName('input');
}
 
function select_all(name, value) {
  for (i = 0; i < forminputs.length; i++) {
    // regex here to check name attribute
    var regex = new RegExp(name, "i");
    if (regex.test(forminputs[i].getAttribute('name'))) {
      if (value == '1') {
        forminputs[i].checked = true;
      } else {
        forminputs[i].checked = false;
  }
    }
  }
}
 
if (window.addEventListener) {
  window.addEventListener("load", prepare, false);
} else if (window.attachEvent) {
  window.attachEvent("onload", prepare)
} else if (document.getElementById) {
  window.onload = prepare;
}
 
//--></script>
</head>
 
<body>
 
<form id="form_id" name="myform" method="get" action="search.php">
 
  <a href="#" onClick="select_all('area', '1');">Check All Fruit</a> | <a href="#" onClick="select_all('area', '0');">Uncheck All 
Fruit</a><br><br>
 
  <input type="checkbox" name="area[]" value="1" />Apples<br />
  <input type="checkbox" name="area[]" value="2" />Bananas<br />
  <input type="checkbox" name="area[]" value="3" />Chickens<br />
  <input type="checkbox" name="area[]" value="4" />Stoats
 
  <br><br><a href="#" onClick="select_all('location', '1');">Check All Locations</a> | <a href="#" onClick="select_all('location', 
'0');">Uncheck All Locations</a><br><br>
 
  <input type="checkbox" name="location[]" value="1" />Brighton<br />
  <input type="checkbox" name="location[]" value="2" />Hove<br />
 
</form>
 
</body>
</html>


]]>
Thu, 28 Jul 2005 10:05:00 +0100 http://www.addedbytes.com/blog/code/select-all-javascript-for-forms-posting-to-an-array/ Dave Child ,,,,,,,,
Writing Secure PHP, Part 3 http://www.addedbytes.com/articles/writing-secure-php/writing-secure-php-3/ In Writing Secure PHP and Writing Secure PHP, Part 2 I covered many of the basic mistakes PHP developers make, and how to avoid common security problems. It is time to get a little deeper into security though, and begin to tackle some more advanced issues.

[Writing Secure PHP is a series. Part 1, Part 2 and Part 4 are currently also available.]

Context

Before I start, it is worth mentioning at this point in this series that much of what is to come is highly dependant on context. If you are running a small personal site and are regularly backing it up, the chances are that there is no real benefit to you spending weeks on advanced security issues. If an attacker can gain nothing (and cause no harm) by compromising your site, and it would only take you ten minutes to restore it, should something go wrong, then it would be a waste to spend too long on security concerns. At the other end of the scale, if you are managing an ecommerce site that processes thousands of credit cards a day, then it is negligent not to spend a lot of time researching and improving your site's security.

Database Field Lengths

Database (we're going to talk about MySQL here, but this is applicable to any database) fields are always of a specific type, and every type has its limits. You can as well, in MySQL, limit field lengths further than they are already limited by their types.

However, to the inexperienced developer, this can present problems. If you are allowing users to post an article on your site, and adding that to a database field with type "blob", then the longest article you can store in the database is 65,535 characters. For most articles that will be fine, but what is going to happen when a user posts an article of 100,000 characters? At best, if you have set up your site so errors are not displayed, their article will simply vanish without being added to the site.

Remember that for an attacker to be able to compromise your system, they need information about it. They need to find weaknesses. Error messages are a very powerful part of that and if you are displaying errors, then an attacker can make use of this to find out information about your database.

To fix this, simply check the lengths of data input through forms and querystrings and ensure that before you launch a site you check forms will not cause errors to be displayed when too many characters are entered.

Weak Passwords

Dictionaries are a useful tool for an attacker. If you have a site with a login system and your database were compromised (and there is no harm in assuming that at some point it will be), an attacker can grab a list of hashed passwords. It is difficult (practically impossible) to directly translate a hash back into a password.

However, most attackers will have databases containing lists of words and their matching hashes in common formats (eg a database with all words in English and their MD5 hashes). It is fairly easy, should someone gain access to your database, for them to compare a hashed password to this list of pre-hashed passwords. If a match is found in the list, the attacker then knows what the un-hashed password is.

There are ways to avoid this problem, and the best of those is to ensure that only strong passwords are ever used. Some people find guaging the strength of passwords tricky, but the general rule of thumb is: a password like "password", "admin", "god", "sex", "qwerty", "123456" or similar (i.e. easily guessable) is extremely weak; a password made up only of a word in the dictionary is weak; a password made of letters, numbers and making use of upper and lower case is strong (there is a strong usability case to be made for not using case-sensitive passwords - if you wish to use case-insensitve ones, simply perform checks to ensure people do not pick passwords like "password12345").

Clients

Clients are a huge security risk, believe it or not. Some will hire a cheaper developer to make small changes six months after you're finished. Some will give out FTP details to anyone who phones and asks for them. [Out of curiosity, I decided to see how easy it is to get FTP details over the phone. I visited the site of a local company (who shall remain nameless) and found the name of their design company (who shall also remain nameless). I then phoned the local company and told them I was with the design company and needed them to send me the site's FTP details. They agreed without question or hesitation. Scary. (I told them what I was doing before they sent any sensitive data to me and they are now better educated and suitably paranoid about people asking for details over the phone).]

Some will ignore emails from people pointing out security problems (in the process of writing the previous article in this series, I found a large selection of sites with publically available database connection scripts. I emailed the owners explaining why they are at risk, and only one has replied and had the problem fixed at the time of writing). Admitedly, many of the emails and calls they receive will be misinformation or sales pitches, but it is still worth them having someone check this out - they do not know enough to distinguish a genuine problem from the rest.

Unfortunately, this is one security problem that cannot be solved with code. This one requires education. For this reason, I have created an unbranded copy of the sheet I give to my clients, with a selection of security tips on. When we launch the site, I sit down with them and tell them how they need to treat their site, and what to consider when making decisions regarding it.

Client Security Handout (PNG, 74KB)

Code Injection (a.k.a. "Cross-Site Scripting")

Unlike SQL Injection, which relies on the use of delimiters in user-input text to take control of database queries, code injection relies on mistakes in the treatment of text before it is output. Or, to put it in simpler terms, code injection is where a malicious user uses a text box to add HTML that they've written to your webpage.

Let's say you have a system that allows users to register as members to your site and that they are allowed to create their own username. They fill out a form, and you insert the data they enter, once you've made it safe to use in a SQL query, into a database. Your members listing page fetches all the usernames from the database and lists them, outputting exactly what is in the database to anyone that views that page.

Now, let's say you've not added a limit to username lengths. Someone could, if they wanted, create a user with the following username:

Username<script type="text/javascript" src="http://www.website.com/malicious.js"></script>

Anyone that then views a page with that username on it will see a normal username, but a JavaScript has been loaded from another site invisibly to the user.

There are plenty of uses for this. First and foremost, it allows attackers to add keyloggers, tracking scripts or porn banners on your site, or just stop your site working altogether. There are several ways to ensure this doesn't happen. First, you could encode HTML in usernames. If you wanted to allow people to use greater-then and less-than signs in their usernames, that is. If not, you can strip these characters out, or strip out HTML tags altogether.

Another, better way to approach this is to limit the character set that can be used in usernames. If you only allow letters and numbers, for example, you could simply use a regular expression in the signup process to validate the username and force the user to pick another if they have disallowed characters in their username. Obviously the problem is not just applicable to usernames - however, as with most other security concerns, being quite paranoid will ensure that you always check data coming from a user before outputting it, and sanitising it in an appropriate way.

Aftermath

Part of a good security strategy is the assumption that at some point everything (and I mean everything) will be deleted or destroyed. It is wise to assume that at some point any security measure you have in place will be compromised. All data may be taken (which is one reason why it is important to encrypt things like passwords and credit card numbers in databases), all files deleted and so on.

One part of PHP development, though perhaps not directly about PHP security, is ensuring that after a catastrophic failure a site can be brought back online quickly. While downtime of four hours maybe acceptable with a low-traffic point-of-presence site, any ecommerce retailer is going to erupt with fury at the thought of that much lost revenue.

Dealing with the client under these circumstances is the first step. Often, your first inkling of a problem with a site may actually come from the client. They may have phoned you and could be angry, worried, or a myriad of other emotions. At moments like this, you would be very glad to have a clear contigency plan in place. Many developers panic when the client phones saying their front page has been defaced. Stick to your action plan and to your client you will seem confident and unphased. That will relax them. The plan will also allow you to resolve the problem far faster.

First, find out what happened. Are you dealing with a security breach or has someone at the host company tripped over a power lead? Was the database compromised, or deleted, as a result of an attack or was your server simply unable to cope with too much traffic? You need to know what has happened in order to deal with it - a site going offline could be down to too many factors to just assume it is a security problem.

Assuming this is a security problem, the next step is to reassure the client. Let them know what has happened. If someone got into the database, no problem - all sensitive data is encrypted. If they've uploaded files to your server (quite possible), you'll have to delete all files and restore from a backup.

You've got to find out how the attacker broke into your system. Check log files, if you have access to them. Also, have a look at hacker and cracker web sites - many of them will list successful attacks against servers by various groups (these are often what are sometimes known as "script kiddies" - not hackers as such, but usually exploiting vulnerabilities found by others). You may well find your site listed and that listing will give you invaluable information. Look at other sites brought down by the same group at around the same time - you will often spot a theme (e.g. all sites that have been attacked were running the same version of IIS or Apache, were all running phpBB, or all are file repositories running on CFML).

If you are running any third party software on the site, check the distribution site and if necessary get in touch with them, especially if other sites running the same software appear to have been compromised.

It is very important that you fix any hole there may be before you restore the site. It would be wise to add a "We are currently undergoing essential maintenance" page, but do not fully restore the site before you have found out and fixed whatever the problem was - you'll be wasting your time.

Shared Hosting

Shared hosting is much cheaper than dedicated hosting, and is where several sites are all hosted on the same server. Most sites are hosted this way, and this brings with it its own set of security issues.

First and foremost, the security of your site is, in these circumstances, almost entirely out of your hands. It is dependant on the hosting company you are with. They may be excellent, or they may be crooks. Check reviews of a company before you select them, as they will have access to all the data you store with them. There is no harm in being automatically suspicious of your hosting company.

If they are completely above board (and most are), you are still not necessarily secure with shared hosting. The security measures they put in place are generally pretty simple. Shared hosting servers should always use PHP's safe mode (which disables many of the more advanced and dangerous features of PHP). That is what it is there for. However, many don't.

Vulnerabilities associated with shared hosting are, for the most part, out of your hands. A badly set up server will allow any site on that server to access files like /etc/passwd and httpd.conf, often giving them access to all other sites on the same server. It is possible to secure yourself to some degree against the effects of this vulnerability. Storing information in a database is recommended. Of course, if you then store your database login in a file, an attacked could access this information. In order to make this inaccessible to others on the same server, you could set database login information within the httpd.conf file, using environmental variables (you will need to ask your host company to add the lines to the httpd.conf file).

Better yet is to ensure that your host, if shared, uses safe mode. While this is still not 100% secure (nothing is), it does help make these attacks more difficult. A dedicated server is another, far better, option, but the expense may be prohibitive.

Ready for more? Try Writing Secure PHP, Part 4.



]]>
Wed, 27 Jul 2005 09:58:00 +0100 http://www.addedbytes.com/articles/writing-secure-php/writing-secure-php-3/ Dave Child ,,,,,,,
PDF Cheat Sheets http://www.addedbytes.com/blog/pdf-cheat-sheets/ As requested by everyone, PDF versions of the PHP, CSS and mod_rewrite cheat sheets are now online. Enjoy!

As requested by everyone, PDF versions of the PHP, CSS and mod_rewrite cheat sheets are now online. Enjoy!



]]>
Fri, 13 May 2005 16:49:00 +0100 http://www.addedbytes.com/blog/pdf-cheat-sheets/ Dave Child ,,
Block Prefetching http://www.addedbytes.com/blog/block-prefetching/ Mozilla and Google's prefetching functions are a nice addition to browser technology in many ways. Unsurprisingly, they are not very well thought through.

Mozilla and Google's prefetching functions are a nice addition to browser technology in many ways. Unsurprisingly, they are not very well thought through. The main two problems with the prefetching idea are that it messes with log files and it means every link on a page could potentially be followed despite the consequences (dangerous in a site administration context).

It appears from the FAQ that Google only intends their accelerator to prefetch specific pages, that have been specified with the <link> tag. However, many people are claiming that normal links have been prefetched.

To prevent prefetching of a page is simple: add the following PHP to the page you do not want prefetched:

if ((isset($_SERVER['HTTP_X_MOZ'])) && ($_SERVER['HTTP_X_MOZ'] == 'prefetch')) {
    // This is a prefetch request. Block it.
    header('HTTP/1.0 403 Forbidden');
    echo '403: Forbidden<br><br>Prefetching not allowed here.';
    die();
}

This will serve a "forbidden" header to the prefetcher. Normal browsing should be unaffected.



]]>
Wed, 20 Apr 2005 16:16:00 +0100 http://www.addedbytes.com/blog/block-prefetching/ Dave Child ,,,,,,
Writing Secure PHP, Part 2 http://www.addedbytes.com/articles/writing-secure-php/writing-secure-php-2/ In Writing Secure PHP, I covered a few of the most common security holes in websites. It's time to move on, though, to a few more advanced techniques for securing a website. As techniques for 'breaking into' a site or crashing a site become more advanced, so must the methods used to stop those attacks.

[Writing Secure PHP is a series. Part 1, Part 3 and Part 4 are currently also available.]

File Systems

Most hosting environments are very similar, and rather predictable. Many web developers are also very predictable. It doesn't take a genius to guess that a site's includes (and most dynamic sites use an includes directory for common files) is an www.website.com/includes/. If the site owner has allowed directory listing on the server, anyone can navigate to that folder and browse files.

Imagine for a second that you have a database connection script, and you want to connect to the database from every page on your site. You might well place that in your includes folder, and call it something like connect.inc. However, this is very predictable - many people do exactly this. Worst of all, a file with the extension ".inc" is usually rendered as text and output to the browser, rather than processed as a PHP script - meaning if someone were to visit that file in a browser, they'll be given your database login information.

Placing important files in predictable places with predictable names is a recipe for disaster. Placing them outside the web root can help to lessen the risk, but is not a foolproof solution. The best way to protect your important files from vulnerabilities is to place them outside the web root, in an unusually-named folder, and to make sure that error reporting is set to off (which should make life difficult for anyone hoping to find out where your important files are kept). You should also make sure directory listing is not allowed, and that all folders have a file named "index.html" in (at least), so that nobody can ever see the contents of a folder.

Never, ever, give a file the extension ".inc". If you must have ".inc" in the extension, use the extension ".inc.php", as that will ensure the file is processed by the PHP engine (meaning that anything like a username and password is not sent to the user). Always make sure your includes folder is outside your web root, and not named something obvious. Always make sure you add a blank file named "index.html" to all folders like include or image folders - even if you deny directory listing yourself, you may one day change hosts, or someone else may alter your server configuration - if directory listing is allowed, then your index.html file will make sure the user always receives a blank page rather than the directory listing. As well, always make sure directory listing is denied on your web server (easily done with .htaccess or httpd.conf).

------

Out of sheer curiosity, shortly after writing this section of this tutorial, I decided to see how many sites I could find in a few minutes vulnerable to this type of attack. Using Google and a few obvious search phrases, I found about 30 database connection scripts, complete with usernames and passwords. A little more hunting turned up plenty more open include directories, with plenty more database connections and even FTP details. All in, it took about ten minutes to find enough information to cause serious damage to around 50 sites, without even using these vulnerabilities to see if it were possible to cause problems for other sites sharing the same server.

-----

Login Systems

Most site owners now require an online administration area or CMS (content management system), so that they can make changes to their site without needing to know how to use an FTP client. Often, these are placed in predictable locations (as covered in the last article), however placing an administration area in a hard-to-find location isn't enough to protect it.

Most CMSes allow users to change their password to anything they choose. Many users will pick an easy-to-remember word, often the name of a loved one or something similar with special significance to them. Attackers will use something called a "dictionary attack" (or "brute force attack") to break this kind of protection. A dictionary attack involves entering each word from the dictionary in turn as the password until the correct one is found.

The best way to protect against this is threefold. First, you should add a turing test to a login page. Have a randomly generated series of letters and numbers on the page that the user must enter to login. Make sure this series changes each time the user tries to login, that it is an image (rather than simple text), and that it cannot be identified by an optical character recognition script.

Second, add in a simple counter. If you detect a certain number of failed logins in a row, disable logging in to the administration area until it is reactivated by someone responsible. If you only allow each potential attacker a small number of attempts to guess a password, they will have to be very lucky indeed to gain access to the protected area. This might be inconvenient for authentic users, however is usually a price worth paying.

Finally, make sure you track IP addresses of both those users who successfully login and those who don't. If you spot repeated attempts from a single IP address to access the site, you may consider blocking access from that IP address altogether.

Database Users

One excellent way to make sure that even if you have a problem with someone accessing your database who shouldn't be able to, you can limit the damage they can cause. Modern databases like MySQL and SQL Server allow you to control what a user can and cannot do. You can give users (or not) permission to create data, edit, delete, and more using these permissions. Usually, I try and ensure that I only allow users to add and edit data.

If a site requires an item be deleted, I will usually set the front end of the site to only appear to delete the item. For example, you could have a numeric field called "item_deleted", and set it to 1 when an item is deleted. You can then use that to prevent users seeing these items. You can then purge these later if required, yourself, while not giving your users "delete" permissions for the database. If a user cannot delete or drop tables, neither can someone who finds out the user login to the database (though obviously they can still do damage).

Powerful Commands

PHP contains a variety of commands with access to the operating system of the server, and that can interact with other programs. Unless you need access to these specific commands, it is highly recommended that you disable them entirely.

For example, the eval() function allows you to treat a string as PHP code and execute it. This can be a useful tool on occasion. However, if using the eval() function on any input from the user, the user could cause all sorts of problems. You could be, without careful input validation, giving the user free reign to execute whatever commands he or she wants.

There are ways to get around this. Not using eval() is a good start. However, the php.ini file gives you a way to completely disable certain functions in PHP - "disable_functions". This directive of the php.ini file takes a comma-separated list of function names, and will completely disable these in PHP. Commonly disabled functions include ini_set(), exec(), fopen(), popen(), passthru(), readfile(), file(), shell_exec() and system().

It may be (it usually is) worth enabling safe_mode on your server. This instructs PHP to limit the use of functions and operators that can be used to cause problems. If it is possible to enable safe_mode and still have your scripts function, it is usually best to do so.

Finally, Be Completely and Utterly Paranoid

Much as I hate to bring this point up again, it still holds true (and always will). Most of the above problems can be avoided through careful input validation. Some become obvious points to address when you assume everyone is out to destroy your site. If you are prepared for the worst, you should be able to deal with anything.

Ready for more? Try Writing Secure PHP, Part 3.



]]>
Tue, 22 Mar 2005 16:53:00 +0000 http://www.addedbytes.com/articles/writing-secure-php/writing-secure-php-2/ Dave Child ,,,,,,,,