-
It’s been worth the wait
A few of us at MxM have waited several weeks for O2 to sort out their supply issue with iPhones for business users (we nearly gave up and bought them as ordinary punters from Carphone Warehouse, but the Free of Charge thing seemed worth hanging on for…).
Here’s a picture of Stuart to show just how delighted he is to be in possession of a 3G iPhone in time for next week’s Rails Europe conference. Face saved.
-
Getting email around spam filters
Sending email programmatically can be tricky, especially if you’re sending it in bulk.
Unless you’re careful it tends to get marked as spam, and the problem is exacerbated by the fact you’re unlikely to know about it – users rarely trawl through their spam folder – and rarer still let you know your email has been caught there.
Solving this problem is a bit of a dark art, like SEO, since spam filters tend to be a bit arbitrary but here are a few tips that will help:
Send from a static IP address:
Email providers often blacklist blocks of dynamic IP addresses since these are often used by spammers. So, make sure you’re sending it from a static IP.Don’t include images
This is a contentious one, but I’ve seen a fair amount of legitimate corporate email sent to the spam folder because of the inclusion of a company logo. I prefer to play it safe and, if possible, only send plain text emails.SPF records
The Sender Policy Framework (SPF) was introduced to combat fake sender addresses, which nearly all abusive e-mail messages carry.I’ve gone to my inbox before, only to find thousands of autoresponders and failed delivery messages. Initially I thought my webserver had been hacked, but instead the spammers were just setting the sender address as my one – to try and make them look more legitimate.
SPF is designed to combat this and allows the owner of a domain to specify their mail sending policy, e.g. which mail servers they use to send mail from their domain. You need to set a SPF record on your domain’s DNS record so receiving servers can check whether the message complies with the domain’s stated policy. You can see SPF at work if you look at an email’s header, you can do this in GMail like this:

Here we can see that Twitter hasn’t configured SPF correctly:
Received-SPF: softfail (google.com: domain of transitioning noreply@twitter.com does not designate 66.7.206.23 as permitted sender) client-ip=66.7.206.23;There are lots of good articles out there, I recommend the easyDNS one, but you should be able to find one specific to your DNS provider.
Reverse DNS Record
Reverse DNS is a way of associating an IP address with its domain name. Email providers often check that the reverse DNS record of the IP that sent an email is the same as the sender’s domain to determine whether the email’s spam (although they generally don’t require that these are the same).Reverse DNS is setup by configuring PTR records (Pointer Records) in your DNS server. To make changed to your Reverse DNS PTR records, you must contact the company where you get your IP addresses from, usually a hosting facility or an ISP.
Try running nslookup on your domain name’s IP – that will show you the Reverse DNS Record.
Here’s the result from 75.101.158.59 (aireohq.com)nslookup 75.101.158.59 Server: 62.140.195.84 Address: 62.140.195.84#53 Non-authoritative answer: 59.158.101.75.in-addr.arpa name = ec2-75-101-158-59.compute-1.amazonaws.com.
This is another problem with sending email from EC2 – the Reverse DNS Record doesn’t match the sender’s domain, and you can’t change the PTR Records to rectify the problem.
MX Records
This one’s really important – most email providers will check the sender domain’s MX Record to see if the server that sent the email is included. You can check the MX Records for your domain like this:
dig -t mx madebymany.co.ukDelegation
Well, the easiestcop outsolution is to delegate your email sending to a SMTP relay like AuthSMTP or easydns. These guys usually send so much email that they have agreements with the major ISPs so their email doesn’t get marked as spam. Don’t forget to configure your SPF record to authorize the relay to send email on your behalf. Paul Dowman has a good tutorial on how to relay mail from an EC2 instance to AuthSMTP through Postfix.There are other ways that mail gets marked as spam, but you can’t influence most of them. Keep checking the SMTP logs to see if mail gets rejected, since usually there’s a helpful explanation.
Does anyone have any other tips?
-
Rails Security Auditing
I’ve recently been doing a bit of Rails auditing, and I thought that I’d just run through the main things I check; all fairly generic attacks that aren’t specific to particular Rails websites.
SQL injection
Actually, I haven’t seem much of this, probably because it’s one of the more well known attacks and people generally seem to be aware of it.ActiveRecord will automatically escape any tainted data, but only if you use the correct syntax:
User.find(:all, :conditions => ['name = ?', params[:name]])All the question marks will get replaced by the escaped name parameter, so your SQL query will be immune to SQL injection attacks.
However, if you were do do something like this:
User.find(:all, :conditions => ["name = #{params[:name]}"])Well, you might as well be giving away your database credentials – an attack can post arbitrary SQL to your webserver, which it will happily execute.
However, it’s not just the :conditions options that is at risk – people sometimes forget to escape tainted strings when passing to :order and :limit (amongst others).
CSRF (Cross Site Request Forgery)
I’ve covered this before on my blog, and the problem has largely been solved with Rails’ built in protection against such attacks.
However, if you’re using GET requests to change state or make destructive actions you’re still at risk. A tell-tale sign is if they’re using :any in routes.rb – and not checking the request method in the controller action, for example:# routes.rb: map.resources :users, :member => {:approve => :any} # user_controller.rb def approve User.find(params[:id]).approve! redirect_to :action => 'index' endSo if Bob gave Alice a url to http://example.com/users/1/approve – Alice would automatically approve that user (if she was logged in).
Usually this attack would be done with a hidden image, so Alice would visit Bob’s innocuous website completely unaware that she had just sent of a request to example.com, approving Bob’s account.
It’s also worth searching for ’skip_before_filter :verify_authenticity_token’ – to see if CSRF has been disabled anywhere.
So, to sum up, make sure the site you’re auditing is using the right HTTP methods, for the right actions; and make sure it’s using an updated Rails version (or using the CSRF killer plugin).
Cross Site Scripting (XSS)
An attacker can exploit XSS to steal session cookies and/or write arbitrary HTML into your website.
If you have any unescaped tainted strings (from the database, for example) displaying on your website, then your site is vulnerable.Do a search for ‘<%=’ on the codebase to quickly find potentially dangerous strings, if the string is tainted (e.g. from params or the db), then it needs to be wrapped in the ‘h’ method, like this:
<%=h @post.body %>Better still, install the xss-shield plugin which will escape everything by default. Hopefully one day Rails will integrate this plugin and this will be less of a problem.
restful_authentication security problem
Last year there was a major security problem with restful-authentication which meant that an attacker would be able to log in without any credentials and use the first account found in the database (probably an admin one too). The plugin was subsequently patched – but it’s worth checking to see which version the site is using.attr_accessor
I’ve saved the most common security flaw until last, not using attr_accessor and attr_protected correctly (or not using them at all).The ActiveRecord method update_attributes is very convenient, and allows you to update your model easily with the request’s parameters. However, this can lead to some unforeseen consequences, like an attacker updating fields you weren’t expecting, like ‘is_admin’ and ‘role’.
The first thing I do when auditing, is to go to Rails schema.rb file (which incidentally I believe should always be checked into source control) and check the ‘users’ table (if there is one). A lot of sites have the ability to make a user an admin, or have different roles for users. It’s very important that those columns are attr_protected – i.e. they can’t be updated with update_attributes.
If they aren’t protected, it’s trivial for an attacker to guess the column name, add a few fields to a form, and make themselves an admin.
So there you have it, the most common security flaws in Rails applications. Can you think of any other ones?
-
Tutorial: Easy Rails recommendations with acts_as_recommendable
Following up on Alex MacCaw’s post on collaborative filtering. The plugin we recently released acts_as_recommendable allows Rails developers to quickly add some user-driven recommendations of items to their latest great millionaire-making startup. At Made By Many we’ve been developing some great niche social-media Ruby On Rails sites recently with New Bamboo and Headshift. The new edge of social media is in the maths, commenting and rating is so old-school, it’s what you do with that data that counts.
This is going to be a tutorial for simple integration of acts_as_recommendable to recommend your users some books.
-
Recommendations & Collaborative Filtering
Data-based recommendations have really revolutionized marketing and web services, making patterns out of the massive amount of information collected about people in order to give them relevant ads, products, friends and music as well as whole host of other things.
Amazon, for example, tracks my browsing history and buying habits to give me a list of products that I’d hopefully be interested in, and usually their algorithm is spot on. I’ve no doubt that recommendations have contributed greatly to their success.
Likewise, Last.fm indexes my music collection and tracks what I listen to in order to give me recommendations about music I haven’t listened to. Like Amazon, they’re usually give pretty good recommendations.
Delicious is an example of a site that doesn’t make the most of the data it collects. With the amount of sites I’ve bookmarked with their service I’m sure they know what I’m interested in and give me relevant recommendations. Perhaps the data processing power needed is what’s holding them back?
ReadWriteWeb has got a good article on Collaborative Filtering and makes an important point about The Wisdom of Crowds which suggest that “as communities grow, not only does a large (diverse, independent, etc.) community make better decisions than a handful of editors, but the larger a community gets, the better its decisions will be”.
Once you scale past more than a dozen users it soon becomes unpractical to make manual recommendations to people, and computers are pretty good making them themselves. A machine doesn’t need to be ’self aware’ or to actual listen to the music to know what you like. No, what actually usually happens is much more low level – users are grouped based on their listening habits (or whatever else it happens to be), and then users are suggested music based on what other people in their group are listening to.
The fact that it’s so level, means that for a lot of recommendations you don’t need data specific algorithms or code, it’s enough to have a relationship between two entities to get recommendations.
At Made by Many I’ve been working on a plugin for Rails called acts_as_recommendable that makes adding recommendations to your Rails sites a piece of cake! If you have a relationship between books and users, for example, acts_as_recommendable will show you which users are similar and which books a user would probably like to read.
The code is based on the example from the book ‘Programming Collective Intelligence‘ which I really recommend getting. it reveals how collective intelligence can be used in a very practical way with a lot of helpful examples.




