TP done
This commit is contained in:
89
server.js
89
server.js
@@ -7,55 +7,84 @@ const jwt = require('jsonwebtoken');
|
|||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
const SECRET_KEY = "votre_clé_super_secrète_et_longue";
|
||||||
|
|
||||||
// BDD simulée en mémoire
|
// BDD simulée en mémoire
|
||||||
const db = new sqlite3.Database(':memory:');
|
const db = new sqlite3.Database(':memory:');
|
||||||
db.serialize(() => {
|
db.serialize(async () => {
|
||||||
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT)");
|
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT)");
|
||||||
db.run("CREATE TABLE notes (id INTEGER PRIMARY KEY, user_id INTEGER, content TEXT)");
|
db.run("CREATE TABLE notes (id INTEGER PRIMARY KEY, user_id INTEGER, content TEXT)");
|
||||||
// Mot de passe stocké en clair (Faille 1)
|
const passAdmin = await bcrypt.hash('supersecret', 10);
|
||||||
db.run("INSERT INTO users (username, password) VALUES ('admin', 'supersecret')");
|
const passAlice = await bcrypt.hash('password123', 10);
|
||||||
db.run("INSERT INTO users (username, password) VALUES ('alice', 'password123')");
|
const stmt = db.prepare("INSERT INTO users (username, password) VALUES (?, ?)");
|
||||||
|
stmt.run('admin', passAdmin);
|
||||||
|
stmt.run('alice', passAlice);
|
||||||
|
stmt.finalize();
|
||||||
db.run("INSERT INTO notes (user_id, content) VALUES (2, 'Mon secret personnel')");
|
db.run("INSERT INTO notes (user_id, content) VALUES (2, 'Mon secret personnel')");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function sendResponse(res, statusCode, data = null, message = '', error = null) {
|
||||||
|
res.status(statusCode).json({
|
||||||
|
status: statusCode < 400 ? 'success' : 'error',
|
||||||
|
message: message,
|
||||||
|
data: data,
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function authenticateToken(req, res, next) {
|
||||||
|
const authHeader = req.headers['authorization'];
|
||||||
|
const token = authHeader && authHeader.split(' ')[1];
|
||||||
|
if (!token) return sendResponse(res, 401, null, '', 'Forgot token');
|
||||||
|
jwt.verify(token, SECRET_KEY, (err, user) => {
|
||||||
|
if (err) return sendResponse(res,403,null, '', 'Erreur de connexion');
|
||||||
|
req.user = user;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
return sendResponse(res, 200, null, 'Bienvenue sur mon API !')
|
||||||
|
})
|
||||||
|
|
||||||
// Route de connexion
|
// Route de connexion
|
||||||
app.post('/login', (req, res) => {
|
app.post('/login', (req, res) => {
|
||||||
const { username, password } = req.body;
|
const { username, password } = req.body;
|
||||||
// Faille 2 : Injection SQL (Concaténation directe)
|
const query = "SELECT * FROM users WHERE username = ?";
|
||||||
const query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
|
db.get(query, [username], async (err, row) => {
|
||||||
|
if (err) return sendResponse(res, 500, null, '', "Erreur serveur");
|
||||||
db.get(query, (err, row) => {
|
if (!row) return sendResponse(res, 401, null, '', "Identifiants incorrects");
|
||||||
if (err) return res.status(500).send(err.message);
|
const match = await bcrypt.compare(password, row.password);
|
||||||
if (row) {
|
if (match) {
|
||||||
res.json({ message: "Connecté", userId: row.id });
|
const token = jwt.sign({ id: row.id, username: row.username }, SECRET_KEY, { expiresIn: '1h' });
|
||||||
|
sendResponse(res, 200, token, 'Connexion réussie !')
|
||||||
|
res.json({ token });
|
||||||
} else {
|
} else {
|
||||||
res.status(401).send("Échec");
|
sendResponse(res, 401, null, '', "Identifiants incorrects");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route pour lire une note
|
app.get('/notes/:id', authenticateToken, (req, res) => {
|
||||||
app.get('/notes/:id', (req, res) => {
|
const query = "SELECT * FROM notes WHERE id = ?";
|
||||||
// Faille 3 : Broken Access Control (IDOR)
|
db.get(query, [req.params.id], (err, row) => {
|
||||||
// On ne vérifie pas si la note appartient à l'utilisateur qui la demande
|
if (err) return sendResponse(res, 401, null, '', "Erreur");
|
||||||
const query = `SELECT * FROM notes WHERE id = ${req.params.id}`;
|
if (!row) return sendResponse(res, 404, null, '', "Not found");
|
||||||
db.get(query, (err, row) => {
|
if (row.user_id !== req.user.id) {
|
||||||
if (row) {
|
return sendResponse(res, 403, null, '', "Forbidden");
|
||||||
// Faille 4 : XSS Réfléchi/Stocké (Pas d'échappement de la sortie)
|
|
||||||
res.send(`<h1>Note : ${row.content}</h1>`);
|
|
||||||
} else {
|
|
||||||
res.status(404).send("Note introuvable");
|
|
||||||
}
|
}
|
||||||
|
res.json({ content: row.content });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route pour créer une note (Vulnérable XSS à l'insertion)
|
app.post('/notes', authenticateToken, (req, res) => {
|
||||||
app.post('/notes', (req, res) => {
|
const { content } = req.body;
|
||||||
const { userId, content } = req.body;
|
const userId = req.user.id;
|
||||||
const query = `INSERT INTO notes (user_id, content) VALUES (${userId}, '${content}')`;
|
const stmt = db.prepare("INSERT INTO notes (user_id, content) VALUES (?, ?)");
|
||||||
db.run(query, function(err) {
|
stmt.run(userId, content, function(err) {
|
||||||
if (err) return res.status(500).send(err.message);
|
if (err) return sendResponse(res, 500, null, '', err.message);
|
||||||
res.send("Note créée");
|
const id = this.lastID
|
||||||
|
sendResponse(res, 200, id, 'Note sécurisée créée');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user