Den Vortrag “Security – What rails will and won’t do for you” von Rory McCune im Rahmen von Scotland On Rails 2009 habe ich zum Anlass genommen, den überfälligen Aspekt Sicherheit in meinem laufenden Railsprojekt anzugehen. Der Sprecher benennt XSS- und SQL-Injection-Angriffe als das bei weitem gewichtigste Problem in diesem Zusammenhang.
SQL-Injection
Solange man keine ungeprüften Daten, die potentiell aus Usereingaben stammen in Sql-Statements manuell verpackt, sorgt ActiveRecord dafür, dass alles automatisch sanitized wird. Insofern ist hier Entwarnung angesagt. Konkret heißt das, wenn direktes SQL erzeugt wird, dann NICHT so:
"name='#{@user.name}' and user_id='#{@user.id}'"
sondern SO:
["name='%s' and user_id='%s'", @user.name, @user.id]
Strategien gegen Cross-Site-Scripting
Hier schlägt man uns zwei Möglichkeiten vor:
- Prüfung von Userdaten bei der Eingabe
- Prüfung bei der Ausgabe
Für beide Varianten gibt es Plugins (siehe die Weblinks). Ich habe mich für die zweite Möglichkeit entschieden und safe-erb installiert:
script/plugin install git://github.com/abedra/safe-erb
Es wirft bei jeder un-sanitizeten Ausgabe eines Strings, der aus DB- oder File-IOs stammt eine Fehlermeldung. Das macht das unbeabsichtigte Übergehen von Lücken schwierig. Die h-Helfermethode Escape-t Tags:
<%=h @user.name %>oder
<%= h(@user.name) %>
und sorgt dafür, dass tainted Strings untainted werden, d.h. durch die Prüfung kommen.
Zwei Tücken musste ich überwinden:
a) Daten die mit dem Rails-Fragmentcaching in memcached gespeichert werden, werden automatisch tainted, d.h. als potentiell unsicher eingestuft. Das ist nicht hilfreich, weil die Fragmente natürlich Tags enthalten. J. Roller schlägt in seinem Blog folgende Lösung vor, die die Ausgaben direkt in der memcached-Anbindung untaint-et. Sie wird z.B. in einem Initializer eingetragen:
1 2 3 4 5 6 7 8 9 |
class ActiveSupport::Cache::MemCacheStore logger.info "Installing Memcache-safe_erb Patch" def read_with_untaint(*args) read_without_untaint(*args).untaint end alias_method_chain :read, :untaint end |
b) Bei der Einbettung von Javascript-Schnipseln gab es teilweise Probleme – auch hier darf man natürlich nicht die h-Methode von Rails benutzen, die Tags entfernt, sondern muss den Ergebnisstring untainten:
<%= (observe_field "project_active_#{project.id}", ..., :method => :post).untaint %>

