onsdag 21 oktober 2009

AppSec Research 2010 Challenge 5

Utmaning fem är publicerad på konferenswikin. Tävla och vinn en biljett till nästa års stora konferens i Stockholm.

Och om ni inte orkar tävla så måste ni i alla fall gå in och provköra exemplet :).

måndag 19 oktober 2009

TLS/SSL Cheat Sheet

Ännu ett OWASP-projekt har levererat -- TLS Cheat Sheet. En guide till hur du implementerar TLS/SSL i din applikation.

"This article provides a simple model to follow when implementing transport layer protection for an application. Although the concept of SSL is known to many, the actual details and security specific decisions of implementation are often poorly understood and frequently result in insecure deployments."

Läs guiden här.

söndag 18 oktober 2009

Orizon 2.0 på AppSec 2010 i Sthlm

OWASP-projektet Orizon -- ett verktyg för källkodsanalys -- gör sig redo för att släppa version 2.0 under AppSec Research 2010 i Stockholm.

"A lot of working will be done starting by today in order to reach a next major bump for Owasp AppSEC 2010 in Stockholm."

Läs mer på deras blogg eller kolla in demon nedan.



torsdag 15 oktober 2009

DDS: Programmera med personnummer, del 2

Det är flera som frågat när del två av mitt bloggande om personnummer i IT-system kommer. Förra bloggposten avslutades med att vi fått in ett personnummer innehållande ett 'Y' och jag gav mig på jakt efter sanningen. Kunde svenskar ha personnummer med bokstäver?

Vem bryr sig?
Varför grotta ner sig i formatet på personnummer? Jo, det är ju just sånt här vi försöker lösa när vi bygger system. Det ska fungera för verksamheten, gå att underhålla och vara säkert. Då måste centrala begrepp redas ut och modelleras rätt i koden.

Vad säger Wikipedia?
Jag började där vi alla börjar när vi har fått ett problem på halsen -- Google :). Wikipedia dyker alltid upp i sökträffarna och de har bra info om personnummer.

Svenska personnummer är hårt reglerade av Folkbokföringslagen §18 och Skatteverket. Så här ligger det till (Å=år, M=månad, D=dag, F=födelsenummer, K=kontrollsiffra):

ÅÅMMDD-FFFK - till och med det år personen fyller 99 år
ÅÅMMDD+FFFK - från och med det år personen fyller 100 år

FFF är udda för män, jämn för kvinnor. Om det inte längre finns något FFF att tilldela för ett visst datum så får man ett personnummer med ett närliggande datum i samma månad.

I datorsystem formateras personnummer som ÅÅÅÅMMDDFFFK -- alltså fyra siffror i årtalet och inget skiljetecken. De två första siffrorna är inte del av det egentliga personnumret och ska därför inte vara med i beräkningen av kontrollsiffran.

Samordningsnummer tilldelas personer som inte är eller har varit folkbokförda i Sverige. De fungerar precis som personnummer men man adderar 60 till dagen, dvs DD är mellan 61 och 91.

Vad gav Google mer?
Wikipedia sa tyvärr inget om bokstäver i svenska personnummer. Några sökträffar senare hittade jag Socialstyrelsens termbank, uppgifter om svenska biobanker och diverse RIV-dokument (Regelverk för Interoperabilitet inom Vård och omsorg). Det spräckte direkt mitt tidsestimat på arbetsuppgiften. Tydligen finns också ...
  • Reservnummer
  • Katastrofnummer
  • Tvillingnummer
  • Försöksperson-id
OMG! Hur såg alla dessa nummer ut och vilka av dem förväntades vi hantera?

Vad säger Skatteverket?
Det var dags att lämna tangentbordet och plocka upp telefonen. Skatteverket var ofta refererade på nätet så jag började där. Växeln slussade mig till en expert som i sin tur slussade mig till überexperten på svenska personnummer -- Selimovic Fahrudin. Han slängde in ytterligare en nummertyp i grytan -- GD-nummer -- och redde sen ut en del:

Personnummer har ett fast format och Skatteverket ser till att det inte slarvas på den fronten. Så dyker det upp några bokstäver i ett svenskt personnummer så är det fel.

Samordningsnummer tilldelas av Skatteverket som på begäran av en myndighet men de har bara funnits sedan år 2000. Innan dess fick samma personer istället så kallat Tilldelat personnummer eller TP-nummer. Men det får inte finnas några bokstäver där heller.

GD-nummer tilldelas av Skatteverket till personer som äger fastigheter i Sverige men inte har något personnummer (t ex inte bor här). Jag fick ringa X gånger till Bolagsverket och sen tillbaka till Skatteverket innan jag fick tydlig information om dem. GD stod tidigare för Gemensamma distriktet och fungerade som en "virtuell kommun" i Stockholm. Numer kan man tillhöra Stockholm eller Malmö och 'GD' står inte för något speciellt. Skattesatsen i GD är 25%.

Bolagsverket har ett gäng dokument som säger att GD-nummer är "ett juridiskt nummer där månad är större än 1, t ex 3020002568". Det är fel. GD-nummer är en löpnummerserie som börjar på "3020" och var i oktober 2009 uppe i 3022xxxxxx. Det har jag också fått bekräftat från Bolagsverket. Hur som helst -- inga bokstäver där heller.

Selimovic ansåg att det kunde finnas två rimliga förklaringar till vårt 'Y' i patientens personnummer. Antingen är det ett finskt personnummer eller så är det ett reservnummer.

Finska personnummer
Tillbaka till Wikipedia som mycket riktigt säger att finska personnummer (egentligen personbeteckning) har antingen en siffra eller en bokstav mellan a och y som kontrolltecken. Patienten kunde alltså vara finsk!

Reservnummer
Reservnummer används huvudsakligen för att kunna koppla ihop patient och vårddokumentation när personnummer eller samordningsnummer saknas eller är okänt. Patienter som behöver någon form av reservnummer är nyfödda, utländska medborgare (arbetande eller turister), asylsökande, medvetslösa patienter, förvirrade patienter med flera.

Det är Socialstyrelsen som har hand om reservnummer så det fick bli ett samtal till dem. Där fick jag till slut tag på Leif Forsberg på Patientregistret som är expert på personnummer i sjukvården. Han berättade att reservnummer tyvärr inte har ett fastlagt format utan att Socialstyrelsen endast gått ut med en rekommendation. De rekommenderar ett korrekt födelsedatum samt minst en bokstav i de fyra sista siffrorna för att man inte ska råka skapa ett befintligt personnummer. Det skulle alltså kunna förklara vår mystiske patient!

Men som utvecklare går det ju inte att programmera utifrån en rekommendation. Jag ville veta hur det verkligen såg ut. Den vänlige Leif erbjöd sig då att göra en statistisk körning på hur reservnumren ser ut. Han hittade tre olika varianter av reservnummer i patientregistret för 2008:
  • Ca 12 000 reservnummer hade en eller flera bokstäver i de fyra sista fälten och korrekt födelsedatum
  • Ca 10 000 reservnummer hade ett nummer som börjar med 50-99 och resten är ett löpnummer av olika sort
  • Ca 3 000 reservnummer var bara ett löpnummer
Vår patient skulle alltså kunna ha ett reservnummer.

Katastrofnummer, tvillingnummer, försöksperson-id?
Alla de andra numren -- katastrofnummer, tvillingnummer och försöksperson-id -- verkar bara vara alternativa benämningar på reservnummer.

Lösning på problemet
När vi kommit så här långt kunde vi konstatera att vi sannolikt inte behövde hantera finska personnummer men eventuellt behövde hantera reservnummer som tydligen inte hade något fastlagt format.

Då kom lösningen -- datakällan meddelade att de inte hade några patienter med annat än siffror i personnumret i databasen. Vi riskerade därmed inte att stänga ute någon med reservnummer eftersom reservnummer inte finns i den aktuella databasen :).

Konklusion
Person-id-begreppet är tydligen inte så enkelt som i högskolans programmeringsuppgifter. Luhn-algoritmen är kul att implementera men verkligheten är ett sammelsurium av strikta regler, rekommendationer, synonyma begrepp, gamla begrepp och hundratals administrativa system.


Jag har uppdaterat svenska Wikipedia med det mesta av det jag kom fram till.

Lycka till där ute!

onsdag 7 oktober 2009

SAML 2.0 -- nu interoperabelt

Det är som bekant alltid en lång resa från standard till kommersiella produkter som kan kommunicera med varann. Ta bara web service-resan med WS-I Basic Profile och det faktum att det fortfarande närmast är raketforskning att få .Net och Java att prata SOAP med varann om man vill applicera WS-security och WS-policy. För ett par dagar sedan togs ett viktigt steg när det gäller att få SAML att fungera interoperabelt.

Vad är SAML?
SAML (security assertion markup language) 2.0 har funnits sen 2004 och används typiskt för single sign-on (SSO) i webbappliktioner och webbtjänster. En så kallad Identity Provider kan med hjälp av SAML utfärda säkerhetspåståenden (security assertions) som ett antal Service Providers kan välja att lita på. Såna säkerhetspåståenden kan vara vem du är, när du autentiserade dig, vilket system du använder med mera.


Två tjänsteleverantörer litar på en identitetsleverantör mha SAML.

Varför SAML?
Man kan vilja använda SAML av flera orsaker:
  • Cross-Domain SSO. SSO löses traditionellt med cookies vilket kräver att alla applikationer och tjänster publiceras under den domän kakan gäller för. För att lösa SSO till olika domäner (cross-domain SSO, CDSSO) så behövs SAML.
  • Interoperabilitet. Olika SSO-tekniker och -produkter fungerar dåligt ihop eftersom de har olika sätt att hantera autentisering och sessioner. SAML är ett standardiserat sätt att lösa det på.
  • Auktorisering och spårbarhet i web services. De säkerhetstekniker man ser i WS-security och WS-policy handlar om skydd av information med hjälp av kryptering och elektroniska signaturer. SAML löser problemet med behörighetskontroll och spårbarhet i web services.
  • Federering. Att hantera identiteter över organisationsgränser är svårt. SAML klarar att samla lokala identiteter till en (eller några) federerade identiteter.
Något nytt under solen?
Så varför skriver jag om en fem år gammal teknik? Jo, för bara ett par dagar sen blev interoperabilitetstesterna av ett antal faktiska SAML-produkter klara!

Liberty Alliance har under sommaren samordnat interoperabilitetstesterna i den nya SAML 2.0 v1.5 eGovernment Profile. Myndigheter i Danmark, Nya Zeeland och USA har arbetat fram testkriterierna. Några exempel på detaljnivån:
  • Service Provider Authentication Request MUST be communicated using HTTP Redirect binding
  • Identity Provider Authentication Response MUST be communicated using HTTP POST binding or SOAP Artifact binding
  • Assertion MUST be signed
Och så var det testresultatet då. Följande produkter deltog i och klarade testerna:
  • Entrust IdentityGuard Federation Module 9.2 och Entrust GetAccess 8.0
  • IBM Tivoli Federated Identity Manager (TFIM) 6.2
  • Microsoft Active Directory Federation Services (AD FS) 2.0
  • Novell Access Manager 3.1
  • PingFederate v6.1
  • SAP NetWeaver Identity Management 7.2
  • Siemens DirX Access V8.1

onsdag 30 september 2009

DDS: Programmera med personnummer

I en tidigare bloggpost så introducerade jag tillsammans med Dan Bergh Johnsson begreppet Domändriven säkerhet (DDS). Den här bloggposten utgår från den.


Så kommer då verkligheten. Ett riktigt system ska utvecklas och domändriven säkerhet ska praktiseras. Mitt senaste projekt var en nationell webbapplikation och web service inom svensk sjukvård.


Ett centralt begrepp i vår domänmodell var svenska personnummer. Systemen som anropar tjänsten anger patientens personnummer och personnumret är primärnyckel i databasen.


Därför tog vi en rad beslut för att vår kod ska hantera personnummer korrekt, allt enligt domändriven säkerhet.


  • Personnummer ska heta just 'personnummer' i koden. Detta trots att kodkommentarer, metod-, variabel- och klassnamn i övrigt är på engelska. 'Social security number' betyder något helt annat och 'Personal number' har ingen specifik betydelse. 'Personnummer' är en central del av domänmodellen och måste benämnas rätt i programkoden.
  • Det finns bara en klass som representerar ett personnummer i hela systemet. Den är väl dokumenterad och beskriver på engelska vad ett personnummer är.
  • Inkommande personnummer är förstås strängar men förutom en inledande koll i parsern att storleken är OK så valideras inte inkommande personnummer förrän ett riktigt personnummerobjekt skapas. Därför ska ett sånt objekt skapas så fort som möjligt. Skälet att vi kontrollerar storleken direkt i parsern är att vi vill motverka DoS-attacker som skickar in 1 Mb data i personnummerfältet.
  • Personnummer valideras i fallande komplexitetsordning enligt: längd (12 eller 13 tecken), tillåtna tecken (siffror och '-'), syntax (12 siffror eller 8 siffror '-' 4 siffror) samt semantik (kontrollsiffra enligt Luhnalgoritmen).


Allt väl så. Det var till och med roligt att implementera! Här kommer så min kollega Kalle Gustafssons och min implementation av svenska personnummer i Java. Notera camel case med särskrivning "PersonNummer" :).


package model;

import java.io.Serializable;
import java.util.Calendar;
import java.util.TimeZone;

import model.support.ChecksumSupport;
import support.log.Logger;
import support.log.SystemLogger;

/**
* A class representing a 12 digit Swedish personnummer (Swedish personal
* identification number). To avoid ambiguity the proper Swedish word is chosen
* instead of trying to define an English equivalent.
* <p>
* A personnummer is formatted in the following way:
* YYYYMMDD-BBBX where BBB is a three digit birth number (odd for men, even for women)
* and X is a check digit calculated from the birth date and birth number.
* <p>
* This class can also handle a Swedish samordningsnummer (co-ordination number)
* where the figure for the birthday is increased by the number 60 and then the
* check digit is calculated. For further reading see SKV 707 utg 2.</p>
* <p>
* Instances of this class are immutable value objects.</p>
* <p>
*
* @author Kalle Gustafsson, Omegapoint AB
* @author John Wilander, Omegapoint AB
*/
public class PersonNummer implements Serializable {
private static final long serialVersionUID = -160928058318117179L;

private static final Logger LOG = SystemLogger.getLogger(PersonNummer.class);

private static final int EARLIEST_YEAR = 1840;
private static final TimeZone STOCKHOLM_TIME_ZONE = TimeZone.getTimeZone("Europe/Stockholm");

private final long m_personNummer; // 12 digit no dash

/**
* Create a personnummer from a twelve digit code that may or may not have
* a dash between the date and the extension.
*
* @param code The personnummer
* @throws IllegalArgumentException On invalid input.
*/
protected PersonNummer(String code) throws InvalidPersonNummerException {
validate(code);
if (code.length() == 13) {
code = code.substring(0, 8) + code.substring(9);
}
m_personNummer = Long.parseLong(code);
}

/**
* This is declared package-private for the unit tests.
*/
static long validate(String code) throws InvalidPersonNummerException {
if (code.length() != 12 && (!(code.length() == 13 && code.charAt(8) == '-'))) {
throw new InvalidPersonNummerException("Must be 12 digits", code);
}

if (code.charAt(8) == '-') { // Remove dash if present
code = code.substring(0, 8) + code.substring(9, 13);
}

Calendar c = Calendar.getInstance(STOCKHOLM_TIME_ZONE);
c.clear();
c.setLenient(false);
try {
StringBuilder dateCode = new StringBuilder(code.substring(0, 8));
int coNumCheckInt = Integer.parseInt(dateCode.substring(6, 7));
if (coNumCheckInt > 3) { // Samordningsnummer (co-ordination number) -> date field
// incremented by 60. Read more in Skatteverket SKV 707, utg 2
dateCode.replace(6, 7, Integer.toString(coNumCheckInt - 6));
}

c.set(Integer.parseInt(dateCode.substring(0, 4)), Integer.parseInt(dateCode.substring(4, 6)) - 1, Integer.parseInt(dateCode.substring(6, 8)));

} catch (ArrayIndexOutOfBoundsException e) {
// Thrown by set if any value is out of range
throw new InvalidPersonNummerException(e.getMessage(), code);
} catch (NumberFormatException e) {
throw new InvalidPersonNummerException(e.getMessage(), code);
}

int year;
try {
year = c.get(Calendar.YEAR);
} catch (IllegalArgumentException e) {
// This has happened
throw new InvalidPersonNummerException(e.getMessage(), code);
}

if (year < EARLIEST_YEAR) {
throw new InvalidPersonNummerException("Year cannot be before " + EARLIEST_YEAR, code);
} else if (c.after(Calendar.getInstance(STOCKHOLM_TIME_ZONE))) {
throw new InvalidPersonNummerException("The date is in the future.", code);
}

int extension = 0;
try {
extension = Integer.parseInt(code.substring(8, 12));
} catch (NumberFormatException e) {
throw new InvalidPersonNummerException("The extension is not a number", code);
}
if (extension < 0) {
throw new InvalidPersonNummerException("The extension is less than 0", code);
} else if (extension > 9999) {
throw new InvalidPersonNummerException("The extension is greater than 9999", code);
}

long pid = Long.parseLong(code);
// Validate checksum. Don't include the leading two century digits
if (!ChecksumSupport.validateChecksum(pid % 10000000000L)) {
LOG.warn("Invalid checksum in personnummer: " + code + ". It should be " + ChecksumSupport.calculateChecksum(pid % 10000000000L));
}
return pid;
}

public String get12DigitWithDash() {
return (m_personNummer / 10000L) + "-" + String.format("%04d", m_personNummer % 10000L);
}

public String get12DigitNoDash() {
return "" + m_personNummer;
}

protected String get10DigitNoDash() {
return (get12DigitNoDash().substring(2));
}

protected String get10DigitWithDash() {
return (get12DigitWithDash().substring(2));
}

/**
* Get the personnummer as a 12-digit long.
*/
public long getCode() {
return m_personNummer;
}

@Override
public String toString() {
// Don't change this. Code that parses logs etc assumes that
// personnummers are formatted like this
return get12DigitWithDash();
}

@Override
public boolean equals(Object o) {
return (o != null) && (o instanceof PersonNummer) && (((PersonNummer) o).m_personNummer == m_personNummer);
}

@Override
public int hashCode() {
return (int) m_personNummer;
}
}

Och så supportklassen för beräkning och validering av checksummor enligt Luhnalgoritmen. Man vill gärna ha den som en utilityklass för att underlätta enhetstestning.

package model.support;

/**
* Utility class for validating personnummer-style checksums.
*
* @author Kalle Gustafsson, Omegapoint AB
*/
public final class ChecksumSupport {
/**
* Validate a personnummer style checksum.
* @param code The code to validate. The last digit of the code is the
* checksum.
* @return {@code true} if the checksum is valid.
*/
public static boolean validateChecksum(long code) {
int myChecksum = (int) (code % 10L);
int checksum = calculateChecksum(code / 10L);
return myChecksum == checksum;
}

/**
* Calculate the personnummer style checksum for the code.
*/
public static int calculateChecksum(long code) {
int cs = 0;
int multiple = 2;
while (code > 0) {
int pos = multiple * (int) (code % 10L);
cs += pos % 10 + pos / 10;
multiple = (multiple == 1 ? 2 : 1);
code = code / 10L;
}

// Subtract the sum modulo 10 from 10.
// The remainder becomes the checksum. If the remainder is 10 the checksum i 0.
return (10 - (cs % 10)) % 10;
}
}

Som sagt, allt väl så. Men det kom mera. Plötsligt fick vi ett felmeddelande i produktion. Någon hade angivit en patient med ett personnummer som slutade på 'Y'. Var det en bugg i anropande system? Eller kan personnummer ha bokstäver? Fortsättning följer, i en kommande bloggpost ...

[Uppdatering] Del 2 har utkommit och finns här.

måndag 28 september 2009

770 DDoS-attacker per dygn

Snacket om förra månadens DDoS-attack mot den georgiske bloggaren gick vidare med en uppföljning om mängden DDoS-attacker och vart de riktar sig.


Arbor Networks driver det stora ATLAS-projektet där de samarbetar med 70 % av världens ISP:er för att samla in globala data om maskar, intrång, phishing, botnät och DDoS-attacker.


Arbors analys visar att inte mindre än 770 DDoS-attacker pågick samma dag som attacken mot georgiern. Och i jämförelse var Georgien-attacken ganska blygsam. En asiatisk 3G-operatör utsattes för 30 Gbps trafik, dvs 3 Gb data i sekunden.


DDoS-attacker är en kamp mellan resurser. Attackeraren slåss med sina tusentals fjärrstyrda datorer (bots) och offret försvarar sig med sin nätverks- och serverkapacitet. Tragiskt nog är det billigare att köpa ett kraftfullt bot-nät än ett kraftfullt försvar.


De största botnäten har hundratusentals fjärrstyrda datorer men som tur är används de nästan aldrig för DDoS-attacker utan för att distribuera spam och malware. Frågan är om något företag i världen skulle kunna stå emot en samlad DDoS-attack från 300.000 datorer?


Dark Readings artikel om dagens DDoS-attacker:

http://www.darkreading.com/security/perimeter/showArticle.jhtml?articleID=219100668&cid=RSSfeed