Igår eftermiddag, dagen efter Trafikverket presenterade Läget i trafiken, lanserade SJ en app till Android. Jag började snabbt titta på datatrafiken till och från appen. Precis som i Trafikverkets fall handlar det om ett helt öppet och oskyddat API, dock inte lika exponerat.

SJ exponerade personlig data

Om du tittar lite närmare i svarsdatan från SJ:s API nedan, närmare bestämt i värdefältet för deviceID. Detta innehåller den privata, unika identifieraren för den enhet du använder när en ny bevakning skapas. SJ exponerar alltså denna data, om alla som valt att bevaka tåg via deras app.

Detta är väldigt kritiskt data, som varken Google eller Apple tillåter att utvecklare tillgängliggör. Med informationen, som Theodor nämner i sitt inlägg, är det exempelvis möjligt att skapa, ändra och ta bort andra användares bevakningar.

Jag uppmanar alla användare att ta bort alla sina bevakningar som skapats via appen, tills dess att SJ har säkrat sitt API.

SJ har bemött kritiken via Twitter

“Nu har vi svar. Det finns ingen personlig info i appen, inte ens UD ID. Det vi kallar device ID är endast kopplat till appen. Trots det ska vi göra om den så den blir krypterad så fort som möjligt.” — @SJ_AB

Intressant svar. Inget är fel, men det ska ändå åtgärdas? Detta är fel. Appen skickar UDID i klartext till SJ:s API. Theodor har tydliggjort detta med enkla skärmdumpar i sitt inlägg. Därefter var det dags att bekänna.

“Vi var övertygade om att vi hade rätt. Nu undersöker vi vad detta beror på och ska åtgärda snarast.” — @SJ_AB

Jättebra agerande av marknadsavdelningen tycker jag. Nu hoppas vi bara att SJ först kommunicerar problemet med sina användare och sedan stänger in användardatan snarast.

Uppdatering: SJ har nu säkrat den mest kritiska bristen i sitt API. Men fortfarande skickas iOS-enheters UDID i klartext till och från appen.

Metoder (deprecated)

Första versionen av SJ API fungerar inte längre som dokumenterat nedan. Se dokumentation av SJ API 2.

Get stations

GET /stations.json Returnerar alla stationer. Exempel för /stations.json:

{
    "stations":
    [
        {
            "id": 1,
            "stationName": "Stockholm C",
            "city": "Stockholm C",
            "stationType": "sj"
        },
        …
        {
            "id": 924,
            "stationName": "Stenstorp",
            "city": "Stenstorp",
            "stationType": "sj"
        }
    ]
}

Get station

GET /station/#{id}.json Returnerar given station. Exempel för /station/1.json:

{
    "id": 1,
    "stationName": "Stockholm C",
    "city": "Stockholm C",
    "stationType": "SJ"
}

Get station timetable

GET /stationTimeTable/#{id}.json Returnerar tidtabell för given station. Exempel för /stationTimeTable/1.json:

{
    "id": 1,
    "stationName": "Stockholm C",
    "city": "Stockholm C",
    "stationType": "SJ",
    "arrivals":
        [
        {
            "trainNumber": "11",
            "time":
            {
                "scheduledTime": "2011-09-29T08:16",
                "newTime": "2011-09-29T08:18"
            },
            "track":
            {
                "scheduledTrack": "7",
                "newTrack": ""
            },
            "fromStationName": "Falun C",
            "toStationName": "Stockholm C",
            "stationNames":
            [
                "Falun C",
                "Borlänge C",
                "Säter",
                "Hedemora",
                "Avesta Krylbo",
                "Sala",
                "Uppsala C",
                "Arlanda C",
                "Stockholm C"
            ],
            "cancelled": false
        },
        …
        {
            "trainNumber": "861",
            "time":
            {
                "scheduledTime": "2011-09-29T19:49",
                "newTime":""
            },
            "track":
            {
                "scheduledTrack": "3",
                "newTrack": ""
            },
            "fromStationName": "Uppsala C",
            "toStationName": "Stockholm C",
            "stationNames":
            [
                "Uppsala C",
                "Knivsta",
                "Märsta",
                "Stockholm C"
            ],
            "cancelled": false
        },
        …
        {
            "trainNumber": "10759",
            "time":
            {
                "scheduledTime": "2011-09-29T20:00",
                "newTime": ""
            },
            "track":
            {
                "scheduledTrack": "7",
                "newTrack": ""
            },
            "fromStationName": "Örebro C",
            "toStationName": "Stockholm C",
            "stationNames":
            [
                "Örebro C",
                "Arboga",
                "Köping",
                "Västerås C",
                "Enköping",
                "Bålsta",
                "Sundbyberg",
                "Stockholm C"
            ],
            "cancelled": false
        }
    ],
    "departures":
    [
        {
            "trainNumber": "425",
            "time":
            {
                "scheduledTime": "2011-09-29T08:10",
                "newTime": ""
            },
            "track":
            {
                "scheduledTrack": "10",
                "newTrack": ""
            },
            "fromStationName": "Stockholm C",
            "toStationName": "Göteborg C",
            "stationNames":
            [
                "Stockholm C",
                "Södertälje Syd",
                "Katrineholm C",
                "Skövde C",
                "Alingsås",
                "Göteborg C"
            ],
            "cancelled":false
        },
        …
        {
            "trainNumber": "860",
            "time":
            {
                "scheduledTime": "2011-09-29T20:11",
                "newTime": ""
            },
            "track":
            {
                "scheduledTrack": "3",
                "newTrack": ""
            },
            "fromStationName": "Stockholm C",
            "toStationName": "Uppsala C",
            "stationNames":
            [
                "Stockholm C",
                "Märsta",
                "Knivsta",
                "Uppsala C"
            ],
            "cancelled":false
        }
    ]
}

Get train

GET /train/#{nr}.json Returnerar position för givet tågnummer. Exempel för /train/220.json:

{
    "trainNumber": "220",
    "trainType": "",
    "fromStationName": "Linköping C",
    "toStationName": "Stockholm C",
    "trainPosition":
    {
        "latitude": 59.154098,
        "longitude": 17.762635,
        "timestamp": "2011-10-03T08:09"
    }
}

Get train timetable

GET /trainTimeTable/#{nr}.json Returnerar stationer och position för givet tågnummer. Exempel för /trainTimeTable/538.json:

{
    "trainNumber": "538",
    "trainType": "",
    "fromStationName": "Malmö C",
    "toStationName": "Stockholm C",
    "trainPosition":
    {
        "latitude": 58.417037,
        "longitude": 15.624342,
        "timestamp": "2011-09-28T17:52"
    },
    "stops":
    [
        {
            "station":
            {
                "id": 3,
                "stationName": "Malmö C",
                "city": "Malmö C",
                "stationType": "SJ"
            },
            "arrivalTime":
            {
                "scheduledTime": "2011-09-28T13:09",
                "newTime":""
            },
            "departureTime":
            {
                "scheduledTime": "2011-09-28T13:17",
                "newTime": "2011-09-28T13:37"
            },
            "track":
            {
                "scheduledTrack": "6",
                "newTrack": ""
            },
            "isCancelled" :true,
            "isPassed":true
        },
        …
        {
            "station":
            {
                "id": 1,
                "stationName": "Stockholm C",
                "city": "Stockholm C",
                "stationType": "SJ"
            },
            "arrivalTime":
            {
                "scheduledTime": "2011-09-28T17:39",
                "newTime": "2011-09-28T19:30"
            },
            "departureTime":
            {
                "scheduledTime": "",
                "newTime": ""
            },
            "track":
            {
                "scheduledTrack": "10",
                "newTrack": ""
            },
            "isCancelled": false,
            "isPassed": false
        }
    ],
    "nextStop":7
}

Get subscriptions

GET /subscriptions.json Returnerade tidigare alla bevakningar. Exempel för /subscriptions.json:

{
    "subscriptionsDTO":
    [
        {
            "id": "censurerad",
            "deviceID": "censurerad",
            "deviceType": "Android",
            "fromStationName": "Stockholm C",
            "toStationName": "Malmö C",
            "fromStationID": 1,
            "toStationID": 3,
            "enabled": true,
            "fromTime": "19:25",
            "toTime": "22:28",
            "weekdays":
            [
                "Tuesday",
                "Friday"
            ]
        },
        …
        {
            "id": "censurerad",
            "deviceID": "censurerad",
            "deviceType": "Android",
            "fromStationName": "Västerås C",
            "toStationName": "Katrineholm C",
            "fromStationID": 99,
            "toStationID": 166,
            "enabled": true,
            "fromTime": "06:55",
            "toTime": "08:00",
            "weekdays":
            [
                "Thursday",
                "Monday",
                "Tuesday",
                "Wednesday"
            ]
        }
    ]
}

New subscription

POST /subscriptions.json Skapar ny bevakning. Exempelfrågan:

{
    "enabled":true,
    "deviceType": "iphone",
    "weekdays":
    [
        "Thursday"
    ],
    "deviceID": "censurerad",
    "toStationName": "Uppsala C",
    "fromStationName": "Stockholm C",
    "fromStationID": 1,
    "toStationID": 5,
    "fromTime": "10:41",
    "toTime": "11:41"
}

ger svaret:

{
    "id": "censurerad",
    "deviceID": "censurerad",
    "deviceType": "iphone",
    "fromStationName": "Stockholm C",
    "toStationName": "Uppsala C",
    "fromStationID": 1,
    "toStationID": 5,
    "enabled": true,
    "fromTime": "10:41",
    "toTime": "11:41",
    "weekdays":
    [
        "Thursday"
    ]
}

Andra som skrivit om SJ:s API


För att kommentera det här inlägget, skriv en .