Monday, February 4, 2008

acts_as_list: Don't use ":null => false" for the position column

When using the Rails acts_as_list plugin, you must include a
"position" column for any model that is using the plugin.

In the migration for that model, I had specified the column,
preventing it from being null:

t.integer :position, :null => false

When you try to delete an item from the list, it blows up under
SQLite3 with this error:

SQLite3::SQLException: SQL logic error or missing database: UPDATE
audios SET "created_at" = '2008-02-04 16:19:47', "product_id" = 2,
"position" = NULL, ...

The plugin is removing the item from the list and setting the position
to NULL before deleting it, which causes the SQL update because of
this code:

# Removes the item from the list.
def remove_from_list
  if in_list?
    decrement_positions_on_lower_items
    update_attribute position_column, nil
  end
end

It's not a bug, but it is unexpected, because the very next SQL
command deletes that row.

It's just the nature of having the plugin be called in before_destroy:

before_destroy :remove_from_list

By the way, the acts_as_list is a great example for writing your own
plugin because it has all the Ruby language tricks required, and is
simple to understand.

Friday, January 18, 2008

Attackers automating tests for argument modification / injection

I have on one of my web sites a dynamic page that displays an image supplied as an argument within a web page.

For example, this will display a page of a musical score in a web page:

viewscore.php?name=scores2002/americathebeautiful_3pm_p1.gif

Yes, it's written in PHP, but the language doesn't matter...

I thought that I was relatively safe from attacks because this is a custom page, not one that is from an open source project that might develop a known weakness.

The page is carefully written to:

* Only accept the one "name" argument.
* To validate it against a regular expression
* To check to see that the score really exists on disk
* Some other checks.

I have it email me when one of these conditions fails.  Particularly if the score page doesn't exist, it could mean that I forgot to post it, or put it in the wrong place.

Lately I've been getting a lot of emails like this:
========
Bad Name
Score name: "http://sans-packing.ru/img/jipeqap/ehudute/"
Visitor IP: 169.244.70.147
========

When you go visit the URL the page there shows this PHP (and it's not getting executed):

<?php echo md5("just_a_test");?>

The domains seem legitimate, they'll be unwilling hosts for spammer's images at some point.

If the attack had succeeded, my site would become the destination of spam emails, ruining my site's reputation.

The moral of the story: Even if you're a little niche custom page, you have to assume that you'll be subject to automated probes for weaknesses.

Check your arguments and check them again!

Update: Ok, I think I get it. They want to see if my site will execute the code from the remote site, and that's why the remote site code with "just a test" is plain text php. If my site executes it, it will display a code that they can check for.

Wednesday, December 26, 2007

The limitations of Apple's Ruby Distribution

The Ruby 1.8 included with Apple's Leopard is a great way to get
started in Ruby and Rails programming with no installation effort.
They did a very nice job, and you can use RubyGems to update Rails and
other gems, and even clean up gems that Apple has included as they
become obsolete.

However, once you get to a certain depth of involvement in Ruby, you
will probably want to use your own installation(s) of Ruby and
override the version that Apple provides.

Among the reasons:

* Apple updates reinstall old gems. For example, Security Update
2007-009 v1.1 re-installed updated versions of Rails 1.2 that I had
already removed.

It usually isn't that much of a problem because you can "clean" them
again.

I've updated RubyGems to 1.0.1, and I'm not sure what would happen if
Apple updated the 0.9.5 version that was included with the Leopard
distribution.

(Since RubyGems is updated using: gem update --system )

Once I get into serious development, I'd rather have control over when
the language, RubyGems, gems, etc. are updated. I hold all of this
stable while I change my code so I know where to look when something
breaks. The Apple Ruby updates were bundled with other important
security updates, so you have to install them if you want to keep the
other things secure.

* Until RubyGems 1.0.1, updating RubyGems would break Apple's two-
directory Gem setup.

* I don't like mixing third party gem executables with the Apple
supplied executables in /usr/bin. They should go in /usr/local/bin.
Or if using MacPorts, /opt/local/bin.  Etc.

* The now released Ruby 1.9, will require a separate installation.
It's not ready for production use, but gem authors and Rails core
contributors will want to have this early version for testing.

As 1.9 and the gems (including Rails) that use it reach production
quality, I'll want to install it to make sure my own code works.

Apple will probably not be in a hurry to offer 1.9 as a package. I
can't fault them for that, they should offer stable and well tested
distributions and let early adopters compile their own.

For now, I'm happy to use Apple's pre-installed Ruby (and I'm glad you
can count on a certain level of Ruby and a set of gems for scripting,
too.)

But, it won't be long before I'm back to compiling my own.

Sunday, December 23, 2007

Converting Mac Address Book vCards Using Ruby

For sending out a large number of Christmas emails to family and friends, I wanted to try the commercial Campaign Monitor email service.

The email addresses were in Apple's Address book, in a group called "Christmas 2007" and were on OS 10.4 (Tiger).

Address Book exports vCards, and Campaign Monitor will let you upload a comma delimited file (cdf) like this:

Scott Schram,scott@some-example-domain.foo

First, I exported the Address Book group to a file vCards.vcf and wrote the Ruby program below to convert them to text format.

vCards can include more than one email, and even though there's a way to mark which email you prefer in the group in Address Book, that information is not reflected in the exported vCards.

So, the program extracts all emails, and for those few vCards that have more than one, I just manually edited the text file to remove the unwanted emails.

The vpim gem had errors with the format of the vCards from the 10.4.x Address Book, so I imported them into a 10.5 (Leopard) Address Book, exported them again, and then everything worked fine.

Campaign Monitor worked great, too!

#!/usr/bin/env ruby -v
#
# Requires gem vpim (0.360)
#
require 'vpim/vcard'

infile = File.open("vCards.vcf")
cards = Vpim::Vcard.decode(infile)

cards.sort_by{ |card| card['n'] }.each do |card|
  emails = card.emails.join(" ")
  puts "#{card['fn']},#{emails}"
end

Ruby and Ruby on Rails Rails Book Reviews on Amazon

As I've been learning Ruby and Ruby on Rails, I've written reviews of the books and posted them on Amazon.

So far, I've reviewed:

Everyday Scripting with Ruby: For Teams, Testers and You by Brian Marick
Learning Ruby by Michael Fitzgerald
Ruby Pocket Reference by Michael Fitzgerald
Ruby by Example: Concepts and Code by Kevin Baird

So (along with some other stuff) here's a link to my Ruby and Ruby on Rails book reviews at Amazon.