Tag Archive for 'Magento'

Face Your Competitors Head On (Sort Of)

I wish I’d invented Facebook. Or Twitter. Or Magento. Or the Million Dollar Homepage. But now that someone did invent them, there’s no point in trying anymore. Right? It’s like famous math problems: once someone does prove the Riemann Hypothesis, all the other people working on the topic will need to find another problem to solve. Once a problem is solved, there’s no point in solving it again.


Or is there? Facebook “replaced” FriendSet and MySpace, Magento is still fighting the good fight against oscommerce. Right now, countless small projects are mustering their feature sets, ready to take on the market leaders. The point is not to topple the titans—the sheer inertia of having to change platforms is going to keep them alive—but rather to chip away some market share.

It’s easy to imagine the leading providers as huge ogres and trolls, wielding spiked clubs and crushing you like the little puny ants that you are. Crush, crush, stomp, stomp. You look at their product, and you weep, because there’s no way you can have 2000 features done by December, and the big ogre can just imperceptibly nod in the right direction to add all of your features to their solution. Only better, cheaper and shinier.

And it’s very tempted to be original (just like everybody else), because there are plenty of examples of start-ups that were doing something completely stupid, yet managed to raise funds and find customers. It’s the gold rush mentality all over again: why should I stick around to be a weaver/farmer/carpenter if I can just go to California, where I’m going to pick the river with the gold nuggets, because I’m that good?

Sometimes, it’s easier to sneak past the ogre guarding the treasure. Or to stab him in the back.

Here are a few rivers where you might find gold nuggets:

  • Some people just don’t want to go with the mainstream product. This is the kind of person who would avoid buying an iPhone because everyone else has one. If you’re up against an established product, these people can be an interesting market to tap into.
  • In expanding markets, you don’t need to steal customers. By extension, if someone just had a great idea, there’s still time to jump on the bandwagon: there’s plenty of customers for everyone, and your combined efforts will create awareness for the product category.
  • No matter what you try, you need to be different. There are no perfect imitations: customers will find the differences. If they are not intentional, you end up with a product that tries to imitate another, but fails. If you embrace and advertise your differences, you can actually manage to be better than your competitor on a certain topic.
  • Nobody’s perfect. Not everyone is a technical genius, a marketing ace and a customer support wizard. Find the weaknesses of your competitors, and determine how you can turn them into advantages for your customers.
  • Wait until the time is right. Quite often, established companies are like frogs in boiling water: they don’t notice that the world around them is changing. If several competitors are sitting on a niche activity, they won’t necessarily notice right away if that activity gets the spotlight. You might be watching them from the sidelines, waiting to pounce, thereby gaining the advantage by adapting your strategy to the new trend.
  • You’re someone else. Every company has an image. Maybe your competitor has a hyper-professional image that appeals only to huge corporations. Maybe they have set up an edgy, cuss-words-on-the-corporate-website kind of show that alienates the more serious customers. If you can manage to be who they are not, you might capture those customers who like the products but hate the shopkeeper.

Do you have any interesting experiences to share about moving into a market with established competitor? Do you think is it easier to find a new market, or to find a niche within an existing one?

Die, little ants. Die.

Five Bad Reasons for using Magento

If you’ve been paying any attention at all to the e-Commerce universe the last few months, you’ve heard about Magento. It’s easy to find resources online explaining in great detail why Varien is a metaphorical messiah and Magento is the second coming and you should start using it right now.

logo

I’m not saying that « Magento sucks. » There are plenty of good reasons for using Magento. It’s reliable, backed by an active community and used by many people. There are also bad reasons for choosing it, and if you don’t know better, you will end up being disappointed.

Here are the five bad reasons I hear the most:

1. Magento is « fully customizable » by dummies

Magento is as customizable as any other open source solution : you can code away any issues you have. If you can code, that is. Sure, there’s a fair amount of customization you can achieve without ever leaving the Magento back-office (sometimes at the cost of learning XML), but unless you learn how to code or spend money on it, you can easily reach a hard limit. Don’t choose Magento because you think you’ll be able to do anything you want.

The best way to use Magento is still to pay for someone to customize it for you, and stick to the basic functionality.

2. Magento is a complete e-Commerce package

Magento is just a piece of software. This means that, once installed, you will need to do the marketing yourself, which is hard if you’re not used to internet marketing and don’t have an existing high-traffic web site to rely on. You will have to host your web site (and make backups). And will have to do any administrative tasks related to storing user information too, such as registering with government agencies.

If you don’t want to do any of that, try looking at Selling on Amazon instead.

3. Magento has been used by [large corporation]

The large corporation does not succeed because it used Magento. It succeeds because it can spend money and hire talent to leverage Magento appropriately. There’s work involved in creating a successful e-Commerce site, so make sure you can take whatever steps are necessary to create one with your tool.

Besides, almost every tool has been used by a corporation or another, including homebrew solutions like Amazon’s Obidos. To say that something has been used by a large corporation only means it’s somewhat useful, not necessarily that it’s the best thing around.

4. Magento is free

Oh, please. Magento is cheap, but certainly not free. Even assuming that you have the skills to set up and customize Magento on your own, doing so still takes time. Plus, you need hosting, accounting, logistics, shipping. And selling stuff online involves more work than just plugging products into a web site and waiting for customers to come! Setting up an e-Commerce operation is an investment, no matter how you look at it.

Or, as Jason Cohen has phrased it quite admirably:

Open-source is free like puppies are free. You don’t write a check to get it, but you have to support it for life. Your employee’s time is not free. Working around bugs is not free. Having nothing but the Web of Lies Internet to rely on for tech support is not free.

5. Magento is a complete, standalone product

This sounds like a good idea in theory — a completely standalone solution that can be used by everyone and handles everything: buying, storing, marketing, advertising, selling, invoicing, shipping… until you need to make it talk to other software. If you’re not lucky enough to use a big-name piece of software that has Magento connectors available, the application that handles your inventory or your accounting or your web site will not be connected to your e-Commerce web site.

So, you will either have to pay for a connector to be written, or copy over all the data by hand.

Did you choose Magento for a bad reason? Or did you ever give up on Magento for a bad reason only to find out later that you should have stayed the course? Make sure you mention it in the comments!

Related Posts

  • Hacking Magento : a peek at various common security vulnerabilities and whether Magento is subject to them
  • Jamin-Puech : a Magento-based web site I worked on
  • Seul avec l’Open Source [fr] : why open source is only half the solution, and why your own efforts will make a difference

Jamin-Puech

Jamin-Puech is a French company that designs and sells handbags and jewelry worldwide. Still, people couldn’t buy these handbags online, because the brand had no e-commerce website.

This is where I come in: I was the technical lead of the development team brought together by my employer, Tangane, to build a new e-commerce website for Jamin-Puech. It consists mostly of a custom-skinned Magento website with some additional development in various functionality areas.

The result has been online for a short while now. If you’re interested in handbags:

http://www.jamin-puech.com/eboutique/

Inline Help

Your average user does not know what a trackback is. Yet, WordPress must let experienced users ping trackbacks. How to include trackback information without scaring away the inexperienced users (and possibly even educating them along the way)?

The solution chosen by WordPress is to use slightly more verbosity to describe what trackbacks are:

wordpress-back

By contrast, Magento involves a lot more knowledge than just publishing a blog. While it’s possible to assume that Magento users earn their wages by knowing how to use it, most of the time they only manipulate the system as a side-effect of handling sales in their brick-and-mortar company, or they are new to sales altogether. So, the result is a complex product with outright terse field descriptions that have very complex effects:

magento-backWho, among normal Magento users, knows what a meta keyword or meta description is? Or whether meta keywords are as useful now as they were in the good old days? But that’s not very important, since you could just ignore those fields.

What’s an URL key? Now, even an experienced web developer might have trouble with this one (it’s the equivalent of a WordPress slug, except WordPress displays that “URL key” field as a more easily understood “Permalink: http://www.nicollet.net/2009/05/inline-help/” with the last URL segment editable).

What about the Page Title? What’s the difference between the category name and the page title? Which is displayed where?

Things get even more complex with other areas of Magento. For instance, in a lot of places a given field is disabled and a “Use Config Defaults” checkbox next to it is checked. The problem is that there is no indication about where those configuration defaults can be changed.

Last but not least, there are several classic questions to be asked, such as “Why does this product appear as out-of-stock?” or “Why doesn’t this product appear in this category?” or “How do I set a table rate?” which require careful analysis of the dozen options that might affect the actual state of the item (enabled? present in website? present in category? stock greater that zero? set as in-stock? children items enabled, present in website and set as in-stock? …)

Inline help items

Modern Javascript libraries allow altering an existing page in a non-intrusive manner by decorating the page elements once they are loaded (or when the user asks for help). This means it’s possible to add novice-specific inline help as:

  • Short text snippets under complex or technical items to explain what they are, possibly with a link to the complete explanation.
  • Explanatory tooltips on hovering.
  • See-also links (where do I change this configuration default? where do I set table rates?) placed exactly where the user might be wondering something.
  • Move-along tutorials that detect whether data was entered in certain fields and guide the user to create items, add them to categories, and so on…
  • Troubleshooting checklists (with links) to determine why a product does not appear, or why it appears out of stock.

In fact, it would even be possible for IT companies to provide their customers with customized help messages that match their specific internal processes.

Documentation!

First, let’s see a short example. Consider Magento’s addImageToMediaGallery function, part of the product model class. Here is the complete documentation for that function:

Add image to media gallery

  • access: public
void addImageToMediaGallery (string $file, [string|array $mediaAttribute = null], [boolean $move = false], [boolean $exclude = true])
  • string $file: file path of image in file system
  • string|array $mediaAttribute: code of attribute with type ‘media_image’, leave blank if image should be only in gallery
  • boolean $move: if true, it will move source file
  • boolean $exclude: mark image as disabled in product page view

It’s better than most documentation in Magento (and by that, I mean that it actually exists). It’s still not very good. A few shortcomings are:

  • I don’t need a sentence to tell me that a function named addImageToMediaGallery adds an image to the media gallery of the current product. What I need to know is what the media gallery is (a link to a documentation page about the media gallery could be useful), how I can list all images or remove an image, and so on. Some of these can be guessed (such as getMediaGalleryImages, which I suspect lists all images added to the media gallery so far, or does it?) but others cannot.
  • Telling me that the first argument is a file path is not very helpful, because it does not tell me what a relative path will be relative to. My initial guess would tell me that Magento will use the current file path to resolve relative file paths (just like any other file-using function does), but I would be wrong: developer forum posts tend to indicate that the path is relative to the media/import path within the Magento install instead.
  • Besides, this also does not tell me what happens when I name a file that does not exist. I can guess that an exception is thrown (but I don’t know which exception, so I cannot programmatically handle it) or that the script just dies.
  • Now, media attributes? I don’t know what a media attribute is (or, more precisely, what is the list of usable media attributes). Can I use any value returned by getMediaAttributes and expect it to work? How do I add or remove media attributes, access them from a template, or simply know what media attributes are associated with a default product? Again, a quick link to a concept page, such as “What are media attributes?” would be helpful.
  • Even assuming that I provide a media attribute argument, what will happen? I can guess the media attribute will be bound to the selected image, but is that all or will something else happen? Can I bind several images to the same attribute? What happens if I unbind an image, does it get deleted? How can I unbind images anyway?
  • Moving the image. What happens if it cannot be moved (for instance, no write-access on the original file)? Where is it moved to? Is the operation failsafe (so that if an exception is thrown after the image is added but before the product is saved, the image is not moved) or does it happen right away and lets me deal with keeping things transactional?
  • Why is the image only disabled in the product page view? Does that mean in other places, such as the catalog or search result views, the image is enabled?

When I’m working on code that I want to be safe and robust, these are only a few questions that I ask myself. And this happens about every single function I work with. If the documentation isn’t up to speed on those questions, I’m going to either lose time tracking down the answer on forums and/or in the source code, or press on without an answer and possibly deliver flawed code that doesn’t handle exceptional situations correctly.

As a contrast, consider .NET’s MSDN page for HttpWebRequest.GetResponse. First, it’s too long for me to post it here. Its first section is the equivalent of the entire above Magento documentation: method syntax, parameter types, return type, description of parameter functionality and return value. Then, there’s the section on exceptions, which describes everything that could possibly happen while executing that function and the reason for it happening. Then, there’s the section on remarks explaining various important details such as references to other parts of the library that could be helpful (such as cookie containers), other methods of the object that alter or depend on the calls to the method, words of caution about the use, and so on. And then, there’s a section with typical use examples explaining quickly how the method is expected to be used.

In a similar vein, the PHP documentation itself is also quite detailed. Consider, for instance, array_key_exists. Like MSDN, it contains syntax and basic description, failure case descriptions, general remarks and examples. It also includes user-provided comments about the function that may be useful to developers.

Writing Documentation

It’s not easy. It requires three skills that developers are not necessarily familiar with. First, good documentation is an act of communcation: it must be concise yet explicit and detailed, it must be complete and technical yet simple and clear. It must be written properly, with complete sentences that one can read easily, use simple words where it can and the precise technical or complex word where it must. It must avoid redundant information (such as repeating as-is the name of a function).

Second, good documentation must deal with all the issues at hand. This is difficult because writing the documentation involves deep knowledge about the general design of the software and, in many cases, of the underlying implementation, so that the technical writer may not be aware that the reader will not know what a media gallery is or where more information can be found about it. Adding a search engine to the documentation can be helpful, but it will be of no use if nobody thought about writing a page on media galleries and their basic principles. Documenting code is explaining what is obvious, but thinking about what is obvious is difficult since so much of it seems just natural. In a similar vein, context-dependent behavior (such as relative paths depending on a certain absolute path) should be identified and be made explicit. On the other hand, there are also the parts that nobody thinks about, such as failures. One should always specify in the documentation when a function may fail, and what happens when it fails.

Third, good documentation should serve three different kinds of requests.

  1. I just saw this function in the code. How does it work? Why doesn’t it work? This is the kind of question that a maintenance programmer will ask himself, and information about behavior, invariants and failure cases is always useful.
  2. I need to do this. Will this function help me? This is what the developer wonders: he has a task, and is looking for a solution. Either the function does what he wants and includes a quick example (and tells him about all the pitfalls of doing it this way) or it references another page that does it.
  3. So, how does this entire thing work anyway? This is what the architect wonders. The detailed information, he needs not. The bigger picture, such as the main concepts, the general properties of a module or class, he craves.

Whenever you find yourself writing some documentation, always determine whether all three requests are satisfied accordingly. Include troubleshooting and debugging information, include how-to and tutorial information, and include bigger picture and general design information.

Hacking Magento

My evil hacker side is rampaging the virtual countryside again. This time, I’m scanning Magento for exploits and vulnerabilities. 

If you like what you see here, or if you’re interested by more details about Magento, the web or the business of earning money online, make sure you subscribe to my rss feed to keep up with the latest articles on the topic. 

Anyway, let’s start with the easy stuff.

Eval

Once I download the code, the first step is to look for classic bug-prone functions. One example is the ‘eval’ function, which executes an arbitrary string as PHP code. Were such a function present in the codebase, I could look for ways of subverting the input string so that I can insert my own code in there and take control of the server.

A quick search of the code yields only two uses of ‘eval’, both of them in a google cart function that was deprecated because it was using ‘eval’:

if($value == "true" || $value == "false")
  eval('$this->'.$string.'="'.$value.'";');
else
  eval('$this->'.$string.'="'.$default.'";');

I scan for uses of that function (just in case someone ignored the deprecation) and get no results. Well, that particular exploit won’t be available here.

Exec

Another way is the classic family of shell execution functions: ‘exec’, ‘shell_exec’ and ‘passthru’, as well as the backtick operator that I’ve never actually seen used anywhere. These functions take a string argument and run it as a command on the server. Of course, this requires that the server is not secure and allows arbitrary execution of commands, but at least one server on the internet is bound to have this safety issue and run Magento.

So, if I could then corrupt the arguments to that call, I could have the server run what I want (usually, it would be downloading a PHP file from my own evil server and running that file with a direct query).

The basic ‘exec’ comes up as part of PEAR, mostly with constant string arguments, so no cookie there.

As for ‘shell_exec’, it comes up in Zend for the console adapter (that no sane person would use on the web), also with constant string arguments.

Finally, ‘passthru’ does not come up anywhere.

So, there’s nothing this way either.

SQL Injection

If I can’t take control of the server directly, I could at least get into the site admin, for instance by extracting the admin password from the database (or inserting my own in its place, if it’s encrypted). With access to the back-end, I could upload evil PHP files and get control anyway. So, I could try hammering the database with injection requests.

A quick search for “SELECT … FROM” yields no interesting results (all of them are within Zend, and I’m not going to look for exploits within Zend today). This means that Magento is using Zend for handling requests (by use of Zend_Table and the related functions) in order to reduce the probability of SQL injection. So far so good, but even Zend doesn’t eliminate the risk of SQL injection completely.

For instance, Zend relies on providing variables as arguments to its functions so that it can escape them itself. So, one would do (to build the ‘where’ part of a query):

$select -> where('parent_id > 0 AND user_id = ?', $userId);

But looking at a Magento file (one that’s part of the external API, and handles the users to the API) I find instead:

$select -> where("parent_id > 0 AND user_id = {$user_id}");

This code inserts the text value of $user_id directly into the request without any escaping or even checking, which makes it a possible vulnerability against SQL injection. This is getting excited: can I alter $user_id to get the request to do nasty things? Nope. Even though the SQL statement itself is risky, the variable is protected:

if (is_numeric($user)) {
  $userId = $user;
} else if ($user instanceof Mage_Core_Model_Abstract) {
  $userId = $user->getUserId();
} else {
  return null;
}

There are around 90 occurences of a “where” clause that contains an interpolated string within Magento. Every one of them is a potential security issue. All of them seem to be secured by argument verification, though.

Password Retrieval

Another way of gaining access to the administration panel is simply by getting the password. Joomla! had a vulnerability in this area not so long ago, for instance. Magento uses a fairly straightforward controller dispatch scheme, meaning that the “/admin/index/forgotpassword/” URL maps to functoin “forgotpasswordAction()” in the file “AdminHtml/controllers/IndexController.php”.

Peeking at the code for that function, I soon notice there’s no way I can get through. Unlike the Joomla!, the password is not set by the user, but rather re-generated by the server and sent back to the user. I can’t even insert my own email to receive the password: sending happens using a specific function that uses the user’s mail.

$user->sendNewPasswordEmail();

Another technique would be to somehow predict what password was generated by the server and plug it back in to connect. The password is generated as such:

$pass = substr(md5(uniqid(rand(), true)), 0, 6);

Now, that’s quite interesting. The server first generates an md5 hash: the characters inside the hash are fully random and unpredictable (unless I can somehow identify the initial state of uniqid and rand when I performed the re-generation, but that was designed to be impossible). Then, it selects the first 6 characters of the hash and uses them as the password. This means that the password contains six hexadecimal figures: there are 16 million possible passwords there, which is far weaker than the safety of a 6-character alphanumeric password (64 billion possible passwords) and ridiculous when compared with an 8-character password containing digits, numbers and punctuation (up to 70 million billion possible passwords).

Of course, this is nothing groundbreaking: 16 million possible passwords is plenty to be safe, especially since they’re randomly chosen and therefore impossible to guess without full brute-force. Besides, to do it, you would need to know the administrator username and email (which can be obtained through a minimal amount of social engineering).

Either way, an improved password-generation method would be to use base64_encode to generate alphanumeric passwords instead of just hex passwords like the above:

$pass = substr(base64_encode(md5(uniqid(rand(), true), true)), 0, 6);

This brings back the number of possible passwords to 64 billion, which is beyond brute-force.

This doesn’t eliminate the annoyance of changing the password without a confirmation e-mail: as soon as you know the administrator’s mail, you can generate a new password as often as you want, and you can even do it fast enough to make the “read password from mail and write password in box” process too slow to use the latest password, or even have the mail-sending script burst (because it’s blacklisted for flooding, for instance) and leave the user with no password.

Related Posts



1170 feed subscribers
(readers who polled a feed this week)