August 2009

Aug 24, 2009

200908131139.jpgIt recently came to my attention that there are some gaps in my conceptualization of Drupal security. I was fortunate enough to have this pointed out to me by the Drupal Security Team, and not by a DOS, CSFR, SQL injection or XSS attack. After publicly bemoaning the mild lashing I received, four members of the Drupal community suggested I read Cracking Drupal. One of them even sent me a copy. No other book was even mentioned, which says to me that - considering how recently it was released - the book fills a void of knowledge that was seriously aching for coverage, and fills it well.

Over years of developing, I've become familiar with the various vulnerabilities that make their way into code, but I've never felt like I could build a complete defense. My knowledge has been piecemeal, drawing from documentation, books, interesting conversations and other people's code. In my case, Cracking Drupal did a fantastic job of gluing these pieces together into a comprehensive frame of mind.

What becomes clear very quickly in Cracking Drupal is that Drupal is quite a wily beast that gives developers real incentive to learn security. There are few functions in Drupal whose exclusive purpose is security, and Greg makes it clear that learning how to secure your site has definite side benefits: "When developers learn and use the API, they are not only safer but more effective and more efficient." When you learn how to use different aspects of the Drupal API (forms, translations, helper functions, theming) you gain bits of security as a bonus. If you set out to learn Drupal security, you'll come out the other end with a pretty solid grasp of Drupal APIs. Either way, it's a win.

Cracking Drupal is surprisingly brief. In 134 pages, Greg covers a lot of ground including:

  • An overview of the different types of attacks one is likely to encounter, from physical to social
  • Most (if not all) aspects of the Drupal API that have security implications
  • Coverage of security-related contributed modules
  • An introduction to the Drupal Security Team
  • Demonstrations of exploiting common weaknesses in Drupal modules and how to fix them

An interesting choice is made in Cracking Drupal to keep a somber atmosphere around the subject matter. In almost any other context, this would be an immediate turn-off. I appreciate humor and optimism to drive my enthusiasm when reading. In contrast with other instructional books which end a chapter with a "go for it, get things done!" message, this book ends chapters with lines like "This paranoid perspective is a good one to maintain as you write, review, and implement features on your site." and "Remember that it is nearly impossible to fully protect yourself from a dedicated and persistent attack." and "If nothing else, I hope this chapter has scared you a bit about the realities of just how easy it is to exploit insecure code and sites".

In a book covering attacks that can result in a very serious loss of time and money, this lack of optimism is probably a good thing. And the final chapter, "Un-cracking Drupal" does leave the reader with the sense that something can be done. It's difficult work, but it's doable. Ultimately, I think the book drives home the fact that the most effective way to make a module or theme secure is to do it right from the start.

The title chapter of Cracking Drupal was probably the most lively and hands-on part of the book. I came out of it feeling like I could really enjoy exploiting vulnerabilities for the greater good. Because of this reaction, I think it would have been a good candidate for a first chapter to really whet people's appetites.

Overall, I think Cracking Drupal does a tremendous service to the community by pulling together the most important aspects of Drupal Security into one solid, compact document. While I came into the book having already been introduced to many of the concepts, it filled in a few gaps, and made the subject matter finite and approachable (albeit a little scary). I suspect this book will serve well as a guide and quick reference as I dive into identifying and patching up vulnerabilities in the modules I maintain.

A couple things I learned

While the greatest benefit to this book was the broad, sweeping overview of security, there were a few additional gems that will come in handy later on:

  • There's a lot more to hook_menu() than I was aware of. Good coverage of examples on p.55
  • I didn't realize that you had to exit after using drupal_access_denied(). p.59
  • Ah, db_placeholders() - a useful function for passing a number of variables to db_query() p.65
  • I had no idea there was such a robust node access API. Wow!

Notes in the margin

Below are a few unorganized comments that constitute my wish-list for future versions and complements to the author:

  • Good quote regarding the definition of security: "For this book I’ll define site security as follows: A site is secure if private data is kept private, the site cannot be forced offline or into a degraded mode by a remote visitor, the site resources are used only for their intended purposes, and the site content can be edited only by appropriate users."
  • I would have liked to see more AJAX security strategies and techniques covered.
  • I liked all the Drupal 7 references, gives a good feel as to the direction of things
  • I was surprised that there were not more brutal admonitions about hacking core, but suspect that's because they represent much fewer vulnerabilities than badly designed contrib.
  • I was happy to see some coverage of CVS and DRUSH, namely using CVS to keep code up-to-date
  • Nice coverage of security-related modules starting around p.41
  • A brief mention is made that using mixed-mode SSL is pretty pointless. This is a big deal, I wish it had gotten further coverage.
  • Being more of an optimist, I appreciated this particular phrase: " Every day there are more and more techniques beingdeveloped to attack sites, but every day there are also Drupal users reviewing code and providing new modules and enhancements to core to keep your site safe." Ahh, a glimmer of hope!
  • Would have liked to see more coverage on the use of form tokens. If one must step outside of the forms api, this could be very important
  • I liked that theme safety was covered, and thought the take on it was interesting: Make the theme secure by giving themers no reason to make stupid mistakes.
  • Since the 'Vulnerable' module was patched up in the end, maybe it should actually be named to indicate that it's meant to be a useful module. That would feel more like a practical example.

Aug 11, 2009

I keep running into people who lead more interesting lives than I do. I realize that this is just an elaborate illusion concocted by my mind in an effort to create a useful mental model of another human being who is way to complex too comprehend, but it still gets me down sometimes.

I'm a naturally optimistic person, and there's gears that start spinning whenever I repeatedly run into a source of emotional drainage. Experience has indicated that there's truth to be uncovered in most pain, and that once the truth is found, the pain dissipates to reveal some kind of rich experience.

So, a while back I started thinking about what kind of rich experience envy would leave behind if one found it's real source. I started digging, and found that I could trace envy to very particular things. At different times I've envied genius programmers, beautiful artists, and eloquent speakers. Identifying these qualities is EXTREMELY valuable, because it generates a list of stuff you want to be. I've sat down many a time and tried to make this kind of list off the top of my head, and it's really hard to do. I've also drawn the conclusion that this is a common problem because I know a number of people who are not very satisfied with their current life, but if you ask them what they want instead they can't tell you.

So, experiencing envy gives you some serious clues as to what you might want. The next step is weeding out the parts that only sound good if you don't think about them too much. Consider rock stardom. Sure, all the middle school girls love you, but would you enjoy travelling 8 months out of the year, sacrificing your relationships, practicing hours every day, and playing the same songs over and over to audiences who hate all your new stuff? Knocking down these fuzzy, badly articulated dreams minimizes a lot of the pain associated with envy. What's left is a list of qualities that you genuinely desire.

So, say by doing this sorting we've reduced the pain of envy by about 50%. Dealing with the last 50% requires a little meditation and one very useful piece of information.

Some of the items on your list (like rock stardom for most people) are relatively easy to dismiss. The remaining items require careful weighing of the positives and negatives. The more clear these become, the more you realize how many options you have. We all have lots of options open to us, but most of the time none of it sounds doable or attractive enough to stop what we're doing and switch gears. But if you give it a little thought, they become more tangible. Vacations or camping trips are great for this kind of meditation, I've found.

The bit of information one needs to fully appreciate the qualities one envies in others, and to understand their cost, is the law of 10,000 hours to mastery. Research has shown that for someone to become a master at something, they almost always have to spend 10,000 hours (3 hours a day for 10 years) practicing it. This law holds for Bill Gates and the Beetles. The example that stuck in my mind was that the Beetles performed over a thousand times before that really got the recognition we remember. That's more performances than most bands have in their entire careers. So, when you see a quality in someone else that you want, think about the time it took to obtain that quality. Then, consider what qualities or skills you've been cultivating over the years. Invariably you will have something valuable that the person you envy does not. For me, this completes the deflation of envy. Instead of thinking about the qualities I don't have, I've instead fostered a sense of respect for the work that someone else has dedicated to develop their qualities, as well as recognized what unique qualities I have, and - very important - what qualities I wish to acquire.

I think you can ride this wave of clarity a little further. Now that you know what you want, and you don't have negative feelings associated with your own qualities or the qualities you seek, it's a perfect time to make some decisions about what to do next. Developing skills and qualities takes time, so what do you want to work on? Coming to a decision on this then helps you take advantage of opportunities to develop these.

In my own case, this lead me to leave my job and seek work in a very particular area. I'm now willing to turn down lucrative opportunities for ones that will help me develop the skills and qualities I desire. Being so purposeful means that every time an opportunity presents itself, I have to reflect on how the opportunity might or might not aid in the fulfillment of my goals, which further articulates and evolves them.

This perhaps complex train of thought begins with simple envy. Envy is useful because it's an instinctual - and thus reliable - reaction. I'd encourage anyone who experiences bouts of it to try riding it for a bit and turn it into something positive. And let me know if it works for you too!

Aug 5, 2009

Skip to the video demo

Open the Drupal.org project page for Query-Based Views

One of my first Drupal modules ever was Ajax Table, which gave some rich tools to users who would would normally circumvent Views to create a report or feed by constructing it programmatically. The problem being solved was "what does one do when they need to build a report starting with a query?" The Views answer is to expose everything you need to Views through modular hooks. This is an awesome long-term solution because, once your tables and custom output functions are exposed to Views, they can be used by any other view, and you can combine stuff in really novel, nifty ways.

However, a lot of people don't have the time or expertise to do that. They need to start with a query, and they would normally create a custom function, run the query directly and then generate the output programmatically. I think that there will always be use cases for this, and even if the same report could be created in Views, some people will do it this way simply because it's faster for what they need. Ajax Table was a utility module for these use cases. By running a query through a helper function and passing a couple parameters, users could generate ajax-reloading, searchable, sortable reports with very minimal work. It was handy, and I used it all the time. I still use it for my internal time-keeping / invoicing / proposal generating system.

The functionality was useful enough that I built out a second iteration called Query-Based Views, this one using Drupal configuration instead of straight-up code. I demo-ed the module to my local Drupal User Group, and got some positive responses regarding of the ajax functionality, rapid development and in-line editing. However, the general consensus was that the functionality would make a much greater impact if contributed as a Views plug-in, or as patches to Views itself.

So I shelved the project, thinking that until I knew enough about Views to integrate this, it would be better not to fork efforts.

Then a few days ago it struck me that maybe I should ask Earl Miles (merlinofchaos), the developer of Views, if the idea of starting with a query was actually Views-compatible. I was thinking that maybe the Views query builder was just an element of the UI that could be replaced out with something supplying a raw query. He said that it really wasn't. Too much of the power of Views is derived from abstracting out the query building process into the UI that's there.

That means there's actually room for this type of module. It's true that a lot of functionality is duplicated, but Query-Based Views runs on a different paradigm that's incompatable with Views, so it's reasonable for it to do so. Some specific bits like in-line editing could be abstracted more to be able to work with Views and Q-Views, but as a first effort, I think this module should fit the bill.

So I spent a couple of days porting the Drupal 5 version of Q-Views to Drupal 6, fixed a bunch of bugs and am releasing it as an alpha. The bulk of the code is written by the Chris Shattuck of yesteryear, who was not as well versed in Drupal ways, so if the module is useful enough a code rewrite is in order for a non-alpha / beta release. But as it stands, it's functional and ready to roll.

Video Demo

Q-Views has a lot of functionality, so this is a longer video (20 min). Feel free to skip around, though.

Aug 4, 2009
200908041150.jpg

WebEnabled is really neat, so neat you have to give it a few minutes to sink in.

If you're a Drupal freelancer or web shop, you spin up new Drupal sites all the time. If you've been doing it long enough, you've probably figured out ways to make the process quicker and cleaner. If you've got a team, you've most likely established a system that allows multiple people to work on the same project. You've got a system for demo-ing Drupal to potential clients and for capturing your work so that you don't do the same stuff over and over. However, if you're considering adjusting your current workflow, have some gaps that need to be filled, or are starting from square one, then it's worth your while to meditate on what WebEnabled can do for a moment.

After signing up for WebEnabled, the first thing you'll want to do fire up an 'application'. WebEnabled has a one-click installer, which installs the latest versions of Drupal 6, Drupal 5, Drupal 7 dev or Acquia Drupal. While cool, a one-click installer is not novel in itself. What is novel is the feature set that accompanies the application. You can set up an app on a fresh .webenabled.com sub-domain, or link it up with your own domain. You can share applications with other users, which makes team-driven development a snap. SVN is also supported out of the box, if you roll with version control. Once you have your app set up, you can clone it. Imagine this workflow: You have a few different flavors of sites you work with, say blogs, e-commerce sites and social networking sites. If you start from scratch, you end up running the same configuration every time, installing the same modules, making some basic theme adjustments. If you've been doing this long enough, you've probably got a folder and database set up locally which you copy every time you start a new project. WebEnabled take this one more step: Fully automated cloning, complete with database config changes, a new database and new SSH account. Again, all this with just one click. It's hard to get simpler than that. After its cloned, you can continue to make improvements to the base site.

Okay, so we've got the ability to create a new site and clone it in just a couple of clicks. Perfect for solo folks, but what about managing default installations with a team? Here's one place where the number of options in WE is a little overwhelming, and detracts from the central awesomeness which is that if you want team-driven development, you can have it. For one, you can use integrated Subversion to manage team development with version control. Version control is a common solution to the problem of team development, but you can also connect different WE accounts to the same project to give several team members access to work with files directly.

The above feature set was enough to get me excited, but WE does one more really unique thing that I personally think is brilliant.

In the Drupal community, there's a lot of work sharing that goes on. Users contribute modules, themes, documentation, and support so that other users don't have to go through the same rigamarole that they did. Fixing people's problems is a two-way exchange. You help people, and earn a name for yourself, and perhaps meet some of your other goals (financial or otherwise). One thing I haven't seen is a good method of sharing base installations. Install profiles and the Patterns module can do something similar, but they take time that most folks don't have. People can package up distributions and share those, but maintaining a distribution is a daunting task that's difficult to do well.

WebEnabled allows you to publicly share your default installation, again with one click. What this does, in essence, is elegantly fill this missing gap for a community-based mechanism of sharing base installations. One doesn't need to go so far as to create and maintain a distribution, and updates made to the default install are automatically available, so there's no overhead in making the default install public. A WE account is required to initially import the default install, but because the free WE account allows up to 3 application installs, there's no cost to download. A public URL is given to a shared install, so you can promote the install however you'd like.

A plan is in the works to provide a marketplace so that developers have the option of selling their default installs. This would work in the same fashion as the free / premium theme model. Supporting this model means that people can actually derive some financial motivation to construct good default installs, and that could benefit the Drupal community and help users at all levels.

One more use case - Drupal training

One thing I think is worth mentioning is that WE is being used by at least one Drupal training firm to get their students set up and learning Drupal. It's easy, ubiquitous, and the only thing that you have to help people set up is an SSH browser of some sort. I can see WE being used for all kinds of Drupal training, both by instructors demonstrating, and students following along.

Criticisms and Concerns

From a User Experience standpoint, the interface assumes that you're a seasoned developer, and I think that might be a mistake, especially considering that students and new developers provide some really solid use cases. So, there are some gaps in documentation and some of the messaging was a little cryptic. There were several points during the initial setup where I asked myself 'okay, what's next?' Once I sorted those out, moving forward was reasonably clear.

I get the feeling that WE is still wrapping their head around their target markets. If I hadn't talked to one of the WE developers, the site wouldn't have called out to me to re-think the way I was doing things. It took a longer conversation to get enthusiastic about it, and to think about ways to incorporate WE into my workflow.

At it's core, WE is a hosted solution. While they've got a bit of a head start, with the open availability of Aegir, and with the Garden / Fields Acquia hosting projects, they're going to have some formidable competition in the marketplace really soon. WE is already stepping up their marketing, and that's good to see. WE has the opportunity to fill a real niche amidst some different rising options, but they will need to carve it out and perhaps even define it as they go.

My experience experimenting with WebEnabled left me pretty excited about its future. I can see that it's headed in a good direction, and it already has what appears to be a solid platform for creating default installs, supporting team-based development, and distributing the install packages. WE can be an awesome addition to a Drupal developer or firm's toolbox, and solves some rather difficult problems quite elegantly.

Aug 2, 2009

At DrupalCamp Colorado, Stephanie Pakrul and Jay Wolf spoke about the new module Skinr and how it relates to Panels for theming, and I left the session with a few pleasant goosebumps. For the uninitiated - as I was - Skinr is a module sponsored by Gravitek Labs which allows themes to expose style presets to blocks. The upshot is that once you create a nice style, you can allow users to apply the styles to virtually any area of a page with a couple clicks. This effectively incorporates several principles that have up until this point been applicable mostly to modules, like reuse of code, config-based changes and ... well ... general modularity. I could immediately see that this was an idea with really big potential. Even in its infancy, the Skinr module can do some pretty neat stuff.

Along these lines, Top Notch Themes did a pre-release of their new Fusion theme which incorporates Skinr functionality. The folks at TNT have really been quite genius with their positioning of the Fusion theme, and I think they have really wrapped their minds around where theming is headed over the next couple of years. Their base message is that Fusion is the only theme you'll ever need - a tall order for any one theme, and an interesting proposition. The theme is grid-based and comes in fluid or fixed 960 variety, and a plethora of styles are made available through Skinr for layout and look and feel.

The main purpose of the Fusion base theme, however, is not to provide a look and feel, but rather to supply a solid foundation for sub-themes and - get this - pluggable, extensible style packs (my term). So, instead of having to cut and paste stylesheets and images from one theme to another, instead you paste these style packs in. I really like this idea. Fusion will ship - I believe - with an example sub-theme that looks pretty decent out of the box. Fusion also exposes some nice configuration options you don't see in a lot of themes, like font settings and setting the default text in several areas of the site.

Fusion will be released into Drupal contrib, and then TNT will be selling sub-themes on their site. The fact that they will be moving their themes to Fusion says something really important about Skinr and Fusion. If a leading Drupal company that needs the support of the community to survive is throwing their weight behind these technologies, it's a good indication that it's something to watch very carefully.

I think the move to create a one-size-fits-all, highly modular theme is inevitable, and comes at an excellent time considering how important it is to the Drupal community to attract more designers and themers. I also think it's a daunting task that can be accelerated if there is a model to drive the development commercially, alongside community development, so I appreciate TNT's and Gravitek's roles in this venture. The ability to create 'style packs' (again, my term), is another way that themers can contribute, and Fusion / Skinr will allow designers to do an awful lot of design without worrying about theming. That's pretty powerful stuff.

I'm really looking forward to seeing how this moves forward. TNT and Gravitek have their work cut out for them, but I hope that quickly it will become a minor movement to change the way we look at theming from here on out.

Aug 1, 2009

I spent a little time today exploring some options for improving the internal linking on my blog. I'm not particularly worried about getting my site high up in the Google, but because I regularly add content it's a good sandbox for testing modules and techniques in achieving search engine friendliness.

A huge focus in SEO is getting higher ranking sites to link to yours, called 'incoming links', and the emphasis on this strategy leaves a lot of room for getting an edge using other techniques. In particular, 'internal links' - or links from one of your pages to another - is a technique way less exploited, but also much more under your control. Here's a couple of principles I've picked up over the years:

  • Links from one of your pages to another one is just as valid as a link from an external site. What matters is the PageRank of the page. Think "pages" not "sites"
  • The longevity of links comes into play, so rotating links aren't as effective in the long run as permanent ones
  • You can link to several pages from one page without diluting the PageRank that page passes onto the others, possibly up to a hundred

So, what this calls for is a strategy for easily creating permanent links from one page to another. Also, by linking to new pages from several others you increase the speed of getting indexed (in theory).

Here's what I done:

1. Installed the Related Content module

The Related Content module allows a user to create one-way associations between one node and several others. These associations can then shown in a variety of formats on the node page, or you can use an API to get a list and do your own formatting. To use it, you first have to set up a view and that's used to display a list of nodes to choose from. I thought the implementation was pretty witty, and I've got some ideas for improvements I'd like to see. For example, automated relationships based on keywords, 2-way associations, hiding the current node (so you don't associate the node with itself), supplying a default view, adding a few more formats, and ajax-loaded views so that exposed filters can display. Doesn't look like the module hasn't gotten much love in the last year or so, but it's functional and think it's a great start.

The role this module fills in terms of search engine friendliness is that it allows nodes to permanently link to multiple other nodes. For real users, it also gives them a next step on your pages. For pages with a high bounce rate, it lays out something that might be a bit enticing.

2. Installed the Vocabulary Index module

You can set up Views to create a list of taxonomy terms with links to the term pages, or you can install Vocabulary Index, which does that out of the box, and also includes a count of nodes for each term. This exposes links to vocabulary terms, which then provide internal links back to articles. I see this as another factor in a good internal linking strategy.

3. Installed the Clean Pagination module

Clean Pagination is a module I put together that will change links from /view-list?page=2 to /view-list/2. Google does a good job at indexing query string-ed pages, but it's generally thought that using clean URLs even in pagination is a stronger method. A setting in the module will also change your pagination links to include keyword-rich, more descriptive URLs in pagination links, which get replaced out with plain numbers when the page is loaded. I'm not sure if this is a good idea or not, but makes sense from an accessibility and search engine friendly perspective. Anyway, the option is there.

4. Used the monthly archive view

A monthly archive is an excellent way to generate permanent internal links. By using a monthly archive view (export found here) and adding it as a block, you expose the index pages for spidering. It took me a while to dig this view up, so I've included the code below for Views 2 in Drupal 6. Here's the view:

$view = new view;
$view->name = 'blog_archive';
$view->description = 'Display a list of months that link to content for that month.';
$view->tag = 'default';
$view->view_php = '';
$view->base_table = 'node';
$view->is_cacheable = FALSE;
$view->api_version = 2;
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->override_option('sorts', array(
  'created' => array(
    'id' => 'created',
    'table' => 'node',
    'field' => 'created',
    'order' => 'DESC',
    'granularity' => 'second',
    'relationship' => 'none',
  ),
));
$handler->override_option('arguments', array(
  'created_year_month' => array(
    'id' => 'created_year_month',
    'table' => 'node',
    'field' => 'created_year_month',
    'default_action' => 'summary asc',
    'style_plugin' => 'default_summary',
    'style_options' => array(
      'count' => 1,
      'override' => 1,
      'items_per_page' => '30',
    ),
    'wildcard' => 'all',
    'wildcard_substitution' => 'All',
    'title' => '%1',
    'relationship' => 'none',
    'validate_type' => 'none',
    'validate_fail' => 'not found',
    'default_argument_type' => 'fixed',
  ),
));
$handler->override_option('filters', array(
  'status' => array(
    'id' => 'status',
    'table' => 'node',
    'field' => 'status',
    'operator' => '=',
    'value' => 1,
    'group' => 0,
    'exposed' => FALSE,
    'expose' => array(
      'operator' => FALSE,
      'label' => '',
    ),
    'relationship' => 'none',
  ),
  'type' => array(
    'operator' => 'in',
    'value' => array(
      'blog' => 'blog',
    ),
    'group' => '0',
    'exposed' => FALSE,
    'expose' => array(
      'operator' => FALSE,
      'label' => '',
    ),
    'id' => 'type',
    'table' => 'node',
    'field' => 'type',
    'relationship' => 'none',
  ),
));
$handler->override_option('access', array(
  'type' => 'none',
  'role' => array(),
  'perm' => '',
));
$handler->override_option('title', 'blog archive');
$handler->override_option('items_per_page', 30);
$handler->override_option('use_pager', '1');
$handler->override_option('row_plugin', 'node');
$handler->override_option('row_options', array(
  'teaser' => TRUE,
  'links' => TRUE,
));
$handler = $view->new_display('page', 'Page', 'page');
$handler->override_option('path', 'drupal-blog-archive');
$handler->override_option('menu', array(
  'type' => 'none',
  'title' => '',
  'description' => '',
  'weight' => 0,
  'name' => 'navigation',
));
$handler->override_option('tab_options', array(
  'type' => 'none',
  'title' => '',
  'description' => '',
  'weight' => 0,
));
$handler = $view->new_display('block', 'Block', 'block');
$handler->override_option('arguments', array(
  'created_year_month' => array(
    'id' => 'created_year_month',
    'table' => 'node',
    'field' => 'created_year_month',
    'default_action' => 'summary asc',
    'style_plugin' => 'default_summary',
    'style_options' => array(
      'count' => 1,
      'override' => 0,
      'items_per_page' => '30',
    ),
    'wildcard' => 'all',
    'wildcard_substitution' => 'All',
    'title' => '%1',
    'relationship' => 'none',
    'validate_type' => 'none',
    'validate_fail' => 'not found',
    'default_argument_type' => 'fixed',
  ),
));
$handler->override_option('block_description', 'Archive list');
$handler->override_option('block_caching', -1);