Building a Mini SOC with Node.js & Elasticsearch
I’ve been working on a hands-on project to simulate a basic Security Operations Center (SOC) environment using real log data.
In this project:
- Collected Windows security logs (Event ID 4625 – Failed Login)
- Queried data using Elasticsearch
- Built a backend API with Node.js & Express
- Implemented brute force detection logic based on repeated failed attempts per IP
The system automatically identifies suspicious activity when multiple failed login attempts are detected from the same source.
Example API endpoints:
- /api/logs/failed-login → Retrieve raw failed login events
- /api/detect/bruteforce → Detect potential brute force attacks
This project helped me better understand:
- Log analysis in real-world environments
- Detection engineering basics
- How SIEM-like systems work under the hood
Next steps:
- Build a real-time dashboard
- Add alerting (notifications/logging)
- Expand detection rules
1. Project Setup (in details)
- Create a project folder
- Initialize Node.js:
- npm init -y
Install dependencies:
npm install express @elastic/elasticsearch
2. Create the Server
Create a file:
server.js
Basic setup:
const express = require(‘express’);
const { Client } = require(‘@elastic/elasticsearch’);
const app = express();
const client = new Client({
node: ‘http://localhost:9200’,
auth: {
username: ‘elastic’,
password: ‘YOUR_PASSWORD’
}
});
3. API: Fetch Failed Login Logs
This endpoint retrieves failed login events (Windows Event ID 4625):
app.get(‘/api/logs/failed-login’, async (req, res) => {
try {
const result = await client.search({
index: ‘winlogbeat-*’,
size: 10,
query: {
match: {
“event.code”: “4625”
}
}
});
res.json(result.hits.hits);
} catch (err) {
console.error(err);
res.status(500).send(‘Error’);
}
});
4. API: Brute Force Detection
This endpoint detects suspicious activity based on repeated failed logins per IP:
app.get(‘/api/detect/bruteforce’, async (req, res) => {
try {
const result = await client.search({
index: ‘winlogbeat-*’,
size: 0,
query: {
match: {
“event.code”: “4625”
}
},
aggs: {
by_ip: {
terms: {
field: “source.ip”,
size: 10
}
}
}
});
const buckets = result.aggregations.by_ip.buckets;
const alerts = buckets
.filter(ip => ip.doc_count >= 5)
.map(ip => ({
ip: ip.key,
attempts: ip.doc_count,
alert: “Brute Force Detected”
}));
res.json(alerts);
} catch (err) {
console.error(err);
res.status(500).send(‘Error’);
}
});
app.get(‘/api/detect/bruteforce’, async (req, res) => {
try {
const result = await client.search({
index: ‘winlogbeat-*’,
size: 0,
query: {
match: {
“event.code”: “4625”
}
},
aggs: {
by_ip: {
terms: {
field: “source.ip”,
size: 10
}
}
}
});
const buckets = result.aggregations.by_ip.buckets;
const alerts = buckets
.filter(ip => ip.doc_count >= 5)
.map(ip => ({
ip: ip.key,
attempts: ip.doc_count,
alert: “Brute Force Detected”
}));
res.json(alerts);
} catch (err) {
console.error(err);
res.status(500).send(‘Error’);
}
});
5. Start the Server
Run the server:
node server.js
Server will start on:
6. Test the APIs
Get failed login logs:
http://localhost:3000/api/logs/failed-login
Detect brute force attacks:
http://localhost:3000/api/detect/bruteforce
What This Achieves
This setup provides:
- Real-time log retrieval from Elasticsearch
- Basic threat detection logic
- A foundation for building a SOC dashboard
