Security Best Practices
Relevant source files
The following files were used as context for generating this wiki page:This document outlines the security mechanisms, practices, and potential vulnerabilities within the LostData application, based on an analysis of the source code. The application's security model is centered around session-based authentication and a simple role-based access control (RBAC) system to protect administrative functions.
The primary security components are implemented in server.js, which handles user authentication, session management, and authorization middleware. The frontend in public/index.html interacts with these server-side controls to provide a user interface that adapts based on the user's role.
Authentication and Session Management
Authentication is handled via a single API endpoint that initiates a server-side session. The user's role is determined at login time based on their email address format.
Sources: server.js:13-28
Login Process
A user authenticates by sending a POST request with their email to the /api/login endpoint. The server then determines the user's role: if the email ends with @admin.com, the role is set to 'admin'; otherwise, it is 'chatter'. This information is stored in the server-side session managed by express-session.
A significant security risk is the use of a hardcoded session secret, 'secret-key'. This makes sessions vulnerable to hijacking if the secret is ever exposed.
// server.js:13-17
app.use(session({
secret: 'secret-key',
resave: false,
saveUninitialized: true
}));
Sources: server.js:13-17
The following diagram illustrates the login sequence.
This diagram shows the user login flow and role assignment.
Sources: server.js:24-28, public/index.html:61-72
Logout Process
The /api/logout endpoint destroys the user's session on the server, effectively logging them out.
// server.js:30-33
app.post("/api/logout", (req, res) => {
req.session.destroy();
res.json({ message: 'Logged out' });
});
Sources: server.js:30-33
Authorization and Access Control
Authorization is implemented through a middleware function, isAdmin, which restricts access to certain API endpoints to users with the 'admin' role.
Sources: server.js:35-38
isAdmin Middleware
The isAdmin middleware checks if a user is authenticated and if their role is 'admin'. If the check fails, it returns a 403 Forbidden status. This middleware is the primary mechanism for protecting sensitive operations like creating, updating, deleting, importing, and exporting model data.
// server.js:35-38
const isAdmin = (req, res, next) => {
if (req.session.user && req.session.user.role === 'admin') next();
else res.status(403).json({ message: 'Admin required' });
};
Sources: server.js:35-38
The flow of an incoming request through the isAdmin middleware is as follows:
This diagram shows the logic of the isAdmin middleware.
Sources: server.js:35-38
Protected Endpoints
The following table summarizes the API endpoints that are protected by the isAdmin middleware. Any attempt to access these without a valid 'admin' session will be denied.
| Method | Endpoint | Description |
|---|---|---|
POST | /api/models | Creates a new model record. |
PUT | /api/models/:id | Updates an existing model record. |
DELETE | /api/models/:id | Deletes a model record. |
GET | /api/export/json | Exports all model data as JSON. |
GET | /api/export/csv | Exports all model data as CSV. |
POST | /api/import/csv | Imports model data from a CSV file. |
Sources: server.js:71-120
Client-Side UI Control
The frontend hides or shows administrative buttons based on the user role stored in localStorage. While this provides a better user experience, it is not a security measure. The actual security is enforced by the isAdmin middleware on the server.
// public/index.html:65-70
if (data.role === 'admin') {
document.getElementById('addModelBtn').classList.remove('hidden');
document.getElementById('editBtn').classList.remove('hidden');
document.getElementById('deleteBtn').classList.remove('hidden');
}
Sources: public/index.html:65-70
Data Security and Handling
Data security involves the database connection configuration, data handling during import/export, and the structure of the data itself.
Database Configuration
The application connects to MongoDB using a connection string. It prioritizes a URI from the MONGODB_URI environment variable, which is a security best practice. However, it falls back to a hardcoded local database URL if the environment variable is not set.
// APP/config/db.config.js:2
module.exports = {
url: process.env.MONGODB_URI || "mongodb://127.0.0.1:27017/model_db"
};
Sources: APP/config/db.config.js:2, server.js:21-22
Data Model and History Tracking
The Model schema includes a history array that logs creation and update events. For updates, it records the timestamp, action, user email, and the fields that were modified. This provides an audit trail for changes to model records.
// APP/models/model.model.js:12-13
history: { type: Array, default: [] }
// server.js:74-75
const model = new Model(req.body);
model.history.push({ timestamp: new Date(), action: 'create', user: req.session.user.email, changes: 'Initial creation' });
Sources: APP/models/model.model.js:12-13, server.js:74-75, server.js:83-84
The diagram below shows the entity relationship for the Model schema.
This diagram illustrates the fields defined in the Mongoose schema for a model.
Sources: APP/models/model.model.js:3-14
Permissive CORS Policy
The server is configured with a permissive Cross-Origin Resource Sharing (CORS) policy (origin: "*"), which allows web pages from any domain to make requests to this API. This can pose a security risk and should be restricted to known and trusted origins in a production environment.
// server.js:11
app.use(cors({ origin: "*" }));
Sources: server.js:11
Summary of Security Risks
- Hardcoded Session Secret: The session secret in
server.jsis hardcoded as'secret-key', making sessions vulnerable to hijacking. This should be loaded from a secure environment variable.- Sources: server.js:14
- Insecure Role-Based Access Control: User roles are assigned based on the email address format (
endsWith('@admin.com')). This is not a secure or reliable method for determining administrative privileges and can be easily bypassed if user registration is not strictly controlled.- Sources: server.js:26
- Permissive CORS Policy: The
cors({ origin: "*" })configuration allows requests from any origin, which is a potential security vulnerability. It should be restricted to the specific domain of the frontend application.- Sources: server.js:11
- Lack of Input Sanitization: The application directly uses
req.bodyto create a new Mongoose model (new Model(req.body)). Without proper validation or sanitization, this could be vulnerable to NoSQL injection or other data pollution attacks.- Sources: server.js:73
- Sensitive Data in Seed Files: The
seed.jsfile contains detailed and potentially sensitive information about models, including instructions like "DO NOT MENTION ANYTHING RELATED TO ESCORTS OR IRL BOOKINGS". Storing such data directly in source code is a risk.- Sources: seed.js:10