Looking for big architectures and adventurous sysadmins

Last week, I wrote a post about SSL optimization that showed the big interest people have in getting the absolute best performance from their web servers.

That post was just a small part of the ebook on SSL tuning I am currently writing. This ebook will cover various subjects:

  • algorithms comparison
  • handshake tuning
  • HSTS
  • session tickets
  • load balancers

I test a lot of different architectures, to provide you with tips directly adaptable to your system (like I did previously with Apache and Nginx). But I don’t have access to every system under the sun…

So, if you feel adventurous enough to try SSL optimization on your servers, please contact me, I would be happy to help you!

I am especially interested in large architectures (servers in multiple datacenters around the world, large load balancers, CDNs) and mobile application backends.

And don’t forget to check out the ebook, to be notified about updates!

Advertisements

Harden WordPress using database permissions

Here is a small idea that I would like to throw into the world: most web applications use only one database user for most operations (installation, administration, common usage). Couldn’t we harness the database to protect a bit your data?

How to

This is how you could do it:

  • Create one user (called ‘user’) with full privileges on the database
  • Create another user with no privileges (let’s call him ‘read’)
  • Create a copy of wp-config.php that you will name wp-config-admin.php
  • Write the ‘read’ credentials in the wp-config.php and the normal credentials in wp-config-admin.php (don’t forget to use different auth, secure auth, logged in and nonce keys)
  • Create a copy of wp-load.php that you will name wp-load-admin.php
  • Replace in wp-load-admin.php the reference to wp-config.php by wp-config-admin.php
  • Replace in wp-login.php and wp-admin/* the references to wp-load.php by wp-load-admin.php
  • Now, you can use the admin interface, create posts, etc.
  • Grant some permissions to the ‘read’ database user: GRANT SELECT ON `db`.* TO ‘read’; GRANT INSERT, UPDATE ON `db`.`wp_comments` TO ‘read’;

That was a bit of work, but not that hard! So, what did we do here? We created a user for the admin interface with full privileges on the database (create/update posts, change the taxonomy, approve the comments, etc) and another one for the front end interface, with only read privileges on all tables (that bothers me too, but read on).

This means that SQL injections, either in plugins or in WordPress code (out of the admin panel) will be much harder to implement with this setup. Beware of the custom tables for some plugins. Those will require specific permissions. Depending on the plugin, some could be read only for common usage.

Going further

That’s nice, but not enough in my opinion. As I said, the full select permission for the ‘read’ user bothers me. Couldn’t we restrict a bit the permissions on wp_users? Some of the columns are needed, but do we need to access the user_pass column? Also, the “ALL PRIVILEGES” for ‘user’ is a bit too much. Do we really use the “FILE” privilege (out of SQL injections :D)?

Without further ado, here are the SQL commands you should use:

GRANT SELECT, INSERT, UPDATE ON `db`.`wp_comments` TO ‘read’;

GRANT SELECT ON `db`.`wp_commentmeta` TO ‘read’;

GRANT SELECT ON `db`.`wp_links` TO ‘read’;

GRANT SELECT ON `db`.`wp_options` TO ‘read’;

GRANT SELECT ON `db`.`wp_term_taxonomy` TO ‘read’;

GRANT SELECT ON `db`.`wp_usermeta` TO ‘read’;

GRANT SELECT ON `db`.`wp_terms` TO ‘read’;

GRANT SELECT ON `db`.`wp_term_relationships` TO ‘read’;

GRANT SELECT ON `db`.`wp_postmeta` TO ‘read’;

GRANT SELECT ON `db`.`wp_posts` TO ‘read’;

GRANT SELECT (user_activation_key, id, user_login, user_nicename, user_status, user_url, display_name, user_email, user_registered) ON `db`.`wp_users` TO ‘read’;

REVOKE ALL PRIVILEGES ON `db`.* from ‘user’;

GRANT SELECT, INSERT, DELETE, UPDATE, CREATE, DROP, ALTER, INDEX ON `db`.* TO ‘user’;

With these commands, ‘user’ can only manipulate tables. If you’re an evil DBA, you can even revoke the “CREATE, DROP, ALTER” permission after install, and reactivate them only for upgrades or plugin installation. The ‘read’ user has the same permissions as before on wp_comments, has “SELECT” on all tables except the wp_users. For wp_users, we grant “SELECT” on all columns except the user_pass one.

Thanks to this configuration, even a SQL injection in a plugin will not reach the password hashes! We also removed dangerous permissions like “FILE”. I’d like to prevent timing attacks like “SELECT BENCHMARK(5000000,ENCODE(‘MSG’,’by 5 seconds’));” but i did not figure out what is the right syntax for this (I tried variations around: “revoke execute on function benchmark from read”, without result).

Thankfully, WordPress mostly works with this configuration, and I think that a lot of other applications could be protected like this. Imagine: you could grant insert but not select on the credit card table in an e-commerce application, and process transactions with a background task with the right permissions.

Database privileges are indeed a powerful tool to protect your code from SQL injections. They might require some architectural changes, but the profits can be huge for your security.

Warning your users about a vulnerability

Somebody just told you about a vulnerability in your code. Moreover, they published a paper about it. Even worse, people have been very vocal about it.
What can you do now? The usual (and natural) reaction is to downplay the vulnerability, and try to keep it confidential. After all, publishing a vuln will make your users unsafe, and it is bad publicity for your project, right?

WRONG!

The best course of action is to communicate a lot. Here’s why:

Communicate with the security researcher

Yes, I know, we security people tend to be harsh, quickly flagging a vulnerable project as “broken”, “dangerous for your customers” or even “EPIC FAIL“. That is, unfortunately, part of the folklore. But behind that, security researchers are often happy to help you fix the problem, so take advantage of that!

If you try to silence the researcher, you will not get any more bug reports, but your software will still be vulnerable. Worse, someone else will undoubtedly find the vulnerability, and may sell it to governments and/or criminals.

Vulnerabilities are inevitable, like bugs. Even if you’re very careful, people will still find ways to break your software. Be humble and accept them, they’re one of the costs of writing software. The only thing that should be on your mind when you receive a security report is protecting your users. The rest is just ego and fear of failure.

So, be open, talk to security researchers, and make it easy for them to contact you (tips: create a page dedicated to security on your website, and provide a specific email for that).

Damage control of a public vulnerability

What do you do when you discover the weakness on the news/twitter/whatever?

Communicate. Now.

Contact the researchers, contact the journalists writing about it, the users whining about the issue, write on your blog, on twitter, on facebook, on IRC, and tell them this: “we know about the issue, we’re looking into it, we’re doing everything we can to fix it, and we’ll update you as soon as it’s fixed“.

This will buy you a few hours or days to fix the issue. You can’t say anything else, because you probably don’t know enough about the problem to formulate the right opinion. What you should not say:

  • “we’ve seen no report of this exploited in the wild”, yet
  • “as far as we know, the bug is not exploitable”, but soon it will be
  • “the issue happens on a test server, not in production” = “we assume that the researcher didn’t also test on prod servers”
  • “no worries, there’s a warning on our website telling that it’s beta software”. Beta means people are using it.

Anything you could say in the few days you got might harm your project. Take it as an opportunity to cool your head, work on the vulnerability, test regressions, find other mitigations, and plan the new release.

Once it is done, publish the security report:

Warning your users

So, now, you fixed the vulnerability. You have to tell your users about it. As time passes, more and more people will learn about the issue, so they might as well get it from you.

You should have a specific webpage for security issues. You may fear that criminals might use it to attack your software or website. Don’t worry, they don’t need it, they have other ways to know about software weaknesses. This webpage is for your users. It has multiple purposes:

  • showing that you handle security issues
  • telling which versions someone should not use
  • explaining how to fix some vulnerabilities if people cannot update

For each vulnerability, here is what you should display:

  • the title (probably chosen by the researcher)
  • the security researcher’s name
  • the CVE identifier
  • the chain of events:
    • day of report
    • dates of back and forth emails with the researcher
    • day of fix
    • day of release (for software)
    • day of deploy (for web apps)
  • the affected versions (for software, not web apps)
  • the affected components (maybe the issue only concerns specific parts of a library)
  • how it can be exploited. You don’t need to get into the details of the exploit.
  • The target of the exploit. Be very exhaustive about the consequences. Does the attacker get access to my contacts list? Can he run code on my computer? etc.
  • The mitigations. Telling to update to the latest version is not enough. Some users will not update right away, because they have their own constraints. Maybe they have a huge user base and can’t update quickly. Maybe they rely on an old feature removed in the latest version. Maybe their users refuse to update because it could introduce regressions. What you should tell:
    • which version is safe (new versions with the fix, but also old versions if the issue was introduced recently)
    • if it’s open source, which commit introduced the fix. That way, people managing their own internal versions of software can fix it quickly
    • how to fix the issue without updating (example for a recent Skype bug). You can provide a quick fix, that will buy time for sysadmins and downstream developers to test, fix and deploy the new version.

Now that you have a good security report, contact again the security researchers, journalists and users, provide them with the report, and emphasize what users risked, and how they can fix it. You can now comment publicly about the issue, make a blog post, send emails to your users to tell them how much you worked to protect them. And don’t forget the consecrated formule: “we take security very seriously and have taken measures to prevent this issue from happening ever again”.

Do you need help fixing your vulnerabilities? Feel free to contact me!

Your data is precious

Following LinkedIn’s large password leak, I have seen a dangerous thought spread to friends and colleagues:
“so what if my LinkedIn password has leaked? What can they do? Look for a job for me?”

That is based on wrong assumptions about what an attacker wants and can do. And it is mistaking the low value you get from a service with the value of your data. Your data is PRECIOUS. Maybe not to you. But everything can be sold, and you’ll always find someone interested to buy it. Let’s see a few creative uses of your Linkedin account:

Analyze your data

You might think that what you share is of no use to anyone except potential recruiters, but by mixing your resume, shared links, private messages, all the data you put on the website, I could build a nice profile and sell it to advertisers. Did you put your address and phone number somewhere in your profile? Awesome! I have a lot of targeted advertisements for you!

Obtain access to your other accounts(email, Facebook, Twitter, Viadeo…)

With your email address and your password, I could probably guess the password for other services. Almost nobody has strong and different passwords for every service. Would you like to see your Facebook or Twitter account compromised? I don’t think so.

Oh, remember to use a strong password, or even two factor authenticatiob for email. A lot of password recovery systems sues emails, so if your mailbox is compromised, your accounts will be compromised.

Spam/SEO

Nothing ca be done with your account? oh, you have contacts. And maybe, a well referenced profile. I’d be able to send spam links to all your contacts with the user feed, and put them in your profile, to improve the ranking of my websites. Sure, there’s no harm to you, if you don’t care about losing credibility or annoying your contacts.

Using the contact list

Oh, yes, I could sell your contact list, that’s easy money!

While I’m at it, I could have fun with your friends and colleagues:

  • ask them for money, nude pictures, confidential information, etc.
  • tell them that your email account has been compromised, and that they must address their emails to another address controlled by me
  • obtain access to their accounts with social engineering
You may be insignificant, but that’s not necessary true of your contacts. In social networks, your network has a value, and you must protect it. It is your responsibility to make sure your friends and colleagues don’t get compromised through your account.
It reminds me of the 90s, when I often had this dialogue:
Me-You should put an antivirus and firewall on your computer.
You-Why should I? There’s nothing interesting on my computer, why would anyone want to infect it?
Me-I receive from you 10 emails a day, and all of them contain a virus.”

Jtalk on Rails: editing Javascript in my browser

If you don’t know JTalk yet, you’re missing something. It’s an awesome piece of work: a Smalltalk to Javascript compiler and a Smalltalk editor running in Javascript, IN YOUR BROWSERGo check it out, now!

Now that you’ve played a bit with JTalk, let’s get started.

If you’re like me, you’re a bit annoyed by WebDAV, the proposed solution to save changes to disk. And if you’re like me, you would like to use Jtalk with Rails, and because you’re a lazy ass like me, you use WEBrick instead of Apache for your development.

Let’s hack something up to replace WebDAV!

Create a Rails application

rails new jtalkonrails
cd jtalkonrails
bundle install
rm public/index.html
rails generate controller home index
printf "Jtalkonrails::Application.routes.draw do\n  root :to => \"home#index\"\nend\n" > config/routes.rb

(I should really make a script out of all my rails initialization commands, one of these days…)

Add Jtalk to your application

cd public/
wget http://github.com/NicolasPetton/jtalk/tarball/master --no-check-certificate
tar zxvf master
cp -R NicolasPetton-jtalk-20cd63e/st .
cp -R NicolasPetton-jtalk-20cd63e/js .
cp -R NicolasPetton-jtalk-20cd63e/css .
cp -R NicolasPetton-jtalk-20cd63e/ide .
rm -rf NicolasPetton-jtalk-20cd63e

JTalk stores source code in three forms: Smalltalk code, Javascript code and smaller Javascript code (“*.deploy.js”).

Jtalk hello world: the Counter example

now, edit app/views/layouts/application.html.erb so that it looks like this:

<!DOCTYPE html>
<html>
<head>
  <title>Jtalk On Rails</title>
  <%= stylesheet_link_tag :all %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
  <script src="js/jtalk.js" type="text/javascript"></script>
  <script type="text/javascript"> loadJtalk()</script>
</head>
<body>
<button onclick="smalltalk.Browser._open()">Class browser</button>

<div id="counters"></div>

<script type="text/javascript">
  jQuery(document).ready(function() {'#counters'._asJQuery()._append_(smalltalk.Counter._new())});
</script>
<%= yield %>

</body>
</html>

Here, we included a button to open the code browser, and added a Counter in a div. Oh, I forgot to tell you: Jtalk works seamlessly with JQuery 🙂
Now, go check it out, and you will seee the counter and be able to increase and decrease the value displayed (yes, that’s a counter).

Editing the code

Click on the “Class browser” button to start the IDE. Select the “Examples” category, the “Counter” class, the “actions” method category, and the “increase method”. You will see in the text box below the source code of the increase method:

increase
count := count + 1.
header contents: [:html | html with: count asString]

Edit that method to increase by steps of 2 instead of 1, and hit “Save”. Now, the counter on your page will increase by steps of 2.
Unfortunately, on the next page refresh, you will lose these changes. That’s why the “Commit category” button is there.
It will take the updated files (here, Examples.st, Examples.js and Examples.deploy.js) and make a PUT request to their original URL.

A PUT, you said? Well, I can work something out with a PUT.

Saving the code

Let’s create a new controller, called Uploader:

rails generate controller uploader jtalk

And edit config/routes.rb as follows:

Jtalkonrails::Application.routes.draw do
  root :to => "home#index"
  if Rails.env == 'development'
    put 'st/:id' => 'uploader#jtalk'
    put 'js/:id' => 'uploader#jtalk'
    put 'js/:id.:deploy' => 'uploader#jtalk'
  end
end

Now the PUT requests are redirected to our controller, but only in the development environment. You do not want to make your JS editable from the browser in a production app. DO NOT WANT!

The only thing left is the controller itself:

class UploaderController < ApplicationController

  def jtalk
    path = Rails.root.join('public')
    if(params[:format] == "js")
      path = path.join("js")
    elsif(params[:format] == "st")
      path = path.join("st")
    end

    if(params[:deploy])
      path = path.join(params[:id]+".deploy."+params[:format])
    else
      path = path.join(params[:id]+"."+params[:format])
    end

    File.open(path, "w") do |f|
      f.write(request.body.read())
    end

    head 200
  end

end

Here, we build the file path from the parameters. I use request.body.read() to get the file content because Rails seems to truncate the beginning of the file.

Profit

Now, go back to the web page, click on “Commit category”, and refresh the page. Your changes were saved! You can enjoy editing your frontend directly from the webpage itself, in the code browser, and more importantly, write your whole frontend in Smalltalk! It’s still missing the workflow “edit-try-debug-edit-continue”, but it already feels just like a “normal” Smalltalk environment. It feels like home 🙂

Post Scriptum

If you want to add a new category, it’s easy: create a file Mycategory.js and put it in public/js, with this content:

smalltalk.addClass('Myclass', smalltalk.Object, [], 'Mycategory');

and change your initialization from loadJtalk() to loadJtalk(new Array(“Mycategory.js”)). The new category will now appear in the code browser, and clicking on “Commit category” will create the deployment file and Smalltalk source file.

Rails and oauth-plugin part 2: the consumer

In the previous post, I showed how you could build a provider with oauth-plugin and Rails. Now, I will demonstrate how to build a consumer (it’s a lot easier).

I will assume that your provider is already running on localhost:3000. The consumer will run on localhost:4000 (run it with “rails server -p 4000”).

Here we go!

rails new consumer
cd consumer

Put this in your Gemfile:

source 'http://rubygems.org'
gem 'rails', '3.0.7'
gem 'sqlite3'
gem 'devise'
gem "oauth-plugin", ">= 0.4.0.pre1"

And run these commands:

bundle install
rails generate devise:install
rails generate devise User
rake db:migrate
rails generate controller welcome index
rm public/index.html

And here is your routes.rb:

Provider::Application.routes.draw do
devise_for :users
root :to => "welcome#index"
end

Create the consumer

rails generate oauth_consumer user
rake db:migrate

in app/controllers/oauth_consumers_controller.rb, replace:

before_filter :login_required, :only=>:index

by

before_filter :authenticate_user!, :only=>:index

Uncomment the methods for devise (go_back, logged_in? currentuser=, deny_access!) in app/controllers/oauth_consumers_controller.rb.

Add to app/models/user.rb:

 has_one  :test, :class_name=>"TestToken", :dependent=>:destroy

Now go to http://localhost:3000/oauth_clients/ to register your first application with these parameters:

Name:                 Test consumer
Main Application URL: http://localhost:4000/
Callback URL:         http://localhost:4000/oauth_consumers/test/callback

You’re redirected to http://localhost:3000/oauth_clients/1. It shows:

Consumer Key:      CRcIJ15MwSqlDTxsH8MpO3En4wjaOxkqeofLioH4

Consumer Secret:   C7uci8xkyMShCf4SNXWPclKbBo3ml1Zf2W2XWu4W

Request Token URL: http://localhost:3000/oauth/request_token

Access Token URL:  http://localhost:3000/oauth/access_token

Authorize URL:     http://localhost:3000/oauth/authorize

Now, you need to put the key and secret in config/initializers/oauth_consumers.rb:

 OAUTH_CREDENTIALS={
:test =>{
:key => "CRcIJ15MwSqlDTxsH8MpO3En4wjaOxkqeofLioH4",
     :secret => "C7uci8xkyMShCf4SNXWPclKbBo3ml1Zf2W2XWu4W",
     :expose => true
   }
 }

Create app/models/test_token.rb. This model will store the token for your provider. If you want to provide helpful methods, take inspiration from lib/oauth/models/consumers/services/.

class TestToken < ConsumerToken
TEST_SETTINGS={
:site => "http://localhost:3000",
:request_token_path => "/oauth/request_token",
:access_token_path => "/oauth/access_token",
:authorize_path => "/oauth/authorize"
}

def self.consumer(options={})
@consumer ||= OAuth::Consumer.new(credentials[:key], credentials[:secret], TEST_SETTINGS.merge(options))
end

end

You should now be able to use the URLs “/oauth_consumers/test/client/”, “/oauth_consumers/test/callback”, “/oauth_consumers/test/callback2″,” /oauth_consumers/test/edit”,
and “/oauth_consumers/test”.

Modify the welcome controller t get the provider data:

 class WelcomeController < ApplicationController
 def index
 # cf http://oauth.rubyforge.org/rdoc/classes/OAuth/AccessToken.html
 @consumer_tokens=TestToken.all :conditions=>{:user_id=>current_user.id}
 @token = @consumer_tokens.first.client
 logger.info "private data: "+@token.get("/data/index").body
 end

end

To connect a user to an external service link or redirect them to:

/oauth_consumers/[SERVICE_NAME]

Where SERVICE_NAME is the name you set in the OAUTH_CREDENTIALS hash. This will request the request token and redirect the user to the services authorization screen. When the user accepts the get redirected back to:

/oauth_consumers/[SERVICE_NAME]/callback

That’s it

This tutorial is really short, and could be explained a bit more, but I’ll leave that for another post. You have enough to start tinkering with OAuth. Have fun!

Rails and oauth-plugin part 1: the provider

These days, I have been playing a lot with Oauth and its RoR implementation, oauth-plugin. Its documentation is a bit short, so here is a tutorial to show how to use it, both in provider and consumer mode. And we will even make them communicate with each other.

We will now build an Oauth provider using oauth-plugin for authorization and Devise for authentication. And we will add a controller protected by Oauth.

Starting up

A few instructions to create the application. You won’t need an explanation for this:

rails new provider
cd provider

Put this in your Gemfile:

source 'http://rubygems.org'
gem 'rails', '3.0.7'
gem 'sqlite3'
gem 'devise'
gem "oauth-plugin", ">= 0.4.0.pre1"

And a few more commands:

bundle install
rails generate devise:install
rails generate devise User
rake db:migrate
rails generate controller welcome index
rm public/index.html

And don’t forget ‘root :to => “welcome#index”‘ in config/routes.rb.

Create the provider

rails generate oauth_provider oauth

rake db:migrate

You could put something else than “oauth” as parameter, but for the moment, the generator has some bugs (it always generate the class OauthController, but with a different name). I’ll check more recent versions of the code.

Now, modify config/application.rb and add:

require 'oauth/rack/oauth_filter'
config.middleware.use OAuth::Rack::OAuthFilter

Put in app/models/user.rb:


has_many :client_applications

has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]

Put in app/controllers/oauth_controller.rb:


alias :logged_in? :user_signed_in?

alias :login_required :authenticate_user!

and uncomment authenticate_user.

Put in app/controllers/oauth_clients_controller.rb:

alias :login_required :authenticate_user!

And now some data

Create a new controller:


rails generate controller data index

And now, edit your controller:

class DataController < ApplicationController
  before_filter :oauth_required

  def index
    @data = { "coincoin" => "o< o<" }

    respond_to do |format|
      format.json { render :json => @data }
    end

  end
end

UPDATE

I discovered a few bugs in this tutorial, so here are the fixes.

oauth-plugin needs the function current_user=, so add this to your ApplicationController:

def current_user=(user)
  current_user = user
end

Next, to handle revocation, you need to add this to config/routes.rb:

post 'oauth/revoke'

And at last, you need to fix the rack filter. The current code doesn’t verify the token validity, and lets revoked tokens access your data.
You have to modify lib/oauth/rack/oauth_filter.rb in the oauth-plugin gem folder.
Replace the line 46:

oauth_token = client_application.tokens.first(:conditions=>{:token => request_proxy.token})

by

oauth_token = ClientApplication.find_token(request_proxy.token)

And that’s it!

You now have a working provider. OauthController handles all the communication with the consumers. OauthClientsController manages the registration of new consumers. They both have customizable views: oauth for the authorization part (for users) and oauth clients for the consumers. And you just need the oauth_required filter to manage access to your data.

And now, you can go to /users/sign_up, then /users/sign_in, then /oauth_clients to register a new client application. You just need to give a name for your application, your URL, and a callback URL.

In the next post, we will build a consumer, and this consumer will access the provider’s data.