Suspicious User Session System (SUSS)
This is a suspicious login detection system, the next generation of early warning detection system. The service at this
moment only has a single endpoint which accepts login event details: username, IP address, event id and timestamp.
Important implementation details
- All the distances and speed are returned in miles and miles per hour.
- If previous and/or subsequent events exist, the service will try to determine their location and calculate travel
speed.
- In case the travel speed exceeds 500 mph threshold the travel will be considered suspicious and flags
travelToCurrentGeoSuspicious
or travelFromCurrentGeoSuspicious
will be set to true.
- In case location of a previous or subsequent event can not be determined the travel will also be considered
suspicious.
- If determined location is inaccurate the accuracy radius is added to the distance upon speed calculation.
How to build and run
docker build -t suss -f .infra/docker/Dockerfile .
docker run --rm --name suss -it -p 5000:80 suss
Request examples
curl -X POST http://localhost:5000/v1/event \
-H 'Content-Type: application/json' \
-d '{"username":"ivan","unix_timestamp":1511026500,"event_uuid":"85ad929a-db03-4bf4-9541-8f728fa12e10","ip_address":"8.8.8.8"}'
curl -X POST http://localhost:5000/v1/event \
-H 'Content-Type: application/json' \
-d '{"username":"ivan","unix_timestamp":1511026600,"event_uuid":"85ad929a-db03-4bf4-9541-8f728fa12e11","ip_address":"85.253.237.59"}'
curl -X POST http://localhost:5000/v1/event \
-H 'Content-Type: application/json' \
-d '{"username":"ivan","unix_timestamp":1511126700,"event_uuid":"85ad929a-db03-4bf4-9541-8f728fa12e12","ip_address":"80.253.237.59"}'
Response examples
{
"currentGeo": {
"lat": 59.433,
"lon": 24.7323,
"radius": 3
},
"travelToCurrentGeoSuspicious": true,
"travelFromCurrentGeoSuspicious": false,
"precedingIpAccess": {
"lat": 37.751,
"lon": -97.822,
"radius": 621,
"speed": 201316,
"ip": "8.8.8.8",
"timestamp": 1511026500
},
"subsequentIpAccess": {
"lat": 56.0133,
"lon": 92.7885,
"radius": 62,
"speed": 89,
"ip": "80.253.237.59",
"timestamp": 1511126700
}
}
Unsuccessful responses
400 Bad Request
- provided request has incorrect format or required fields are missing
409 Conflict
- event with this ID has already been recorded
422 Unprocessable Entity
- location can not be determined by the provided event IP
How to run tests
% go test ./...
? github.com/dmitriivoitovich/test-assignment-malwarebytes [no test files]
ok github.com/dmitriivoitovich/test-assignment-malwarebytes/controller (cached)
? github.com/dmitriivoitovich/test-assignment-malwarebytes/controller/request [no test files]
? github.com/dmitriivoitovich/test-assignment-malwarebytes/controller/response [no test files]
? github.com/dmitriivoitovich/test-assignment-malwarebytes/repository [no test files]
? github.com/dmitriivoitovich/test-assignment-malwarebytes/repository/db [no test files]
ok github.com/dmitriivoitovich/test-assignment-malwarebytes/service (cached)
Dependencies
github.com/labstack/echo
- web framework for route, context and error handling and logging
github.com/go-playground/validator/v10
- data validation library, used for input validation
github.com/satori/go.uuid
- uuid data type implementation
github.com/oschwald/geoip2-golang
- geoip data files reader
github.com/umahmood/haversine
- haversine formula implementation
gorm.io/gorm
- ORM library for querying DB
gorm.io/driver/sqlite
- sqlite driver for the ORM
github.com/stretchr/testify
- test framework
github.com/icrowley/fake
- test data generator
Benchmark results
Tests were made with ab (Apache benchmarking tool) on a MacBook Pro 15" 2015
with the following specs:
2,2 GHz Quad-Core Intel Core i7
16 GB 1600 MHz DDR3
Database was tentatively filled with 1M randomly generated events. The DB file size with 1M records occupies about 97 Mb
of disc space, or 101 byte per record.
% ab -c 100 -n 10000 -k -p /tmp/data.json -T 'application/json' http://localhost/v1/event
Requests per second: 840.84 [#/sec] (mean)
Time per request: 118.929 [ms] (mean)
Time per request: 1.189 [ms] (mean, across all concurrent requests)
CPU profiler shows that execution time is mostly spent on DB inserts, which can't be optimised. Further improvements
must be made on the data storage layer: replacement of data storage engine or the structure of data could make a
significant effect on performance.