NML Says

Data Security 9

Model Solution to Exercises from the Previous Lesson

Given the short timespan since the previous lesson we did not expect submissions yet. A model solution is pending until the next lesson.

This Lessons Material

In this lesson we want you to work practically with 2-factor-authentication, 2FA. For this we have quoted two files from a recently submitted project. The two files quoted below are server.js the server side code for the project, and README.md. It is not explicitly copyrighted, but it is declared open source in the README.

Like all code it could be written differently. In the exercise you will be given, we want you to do the same, but reformatted into an MVC architecture.

Both files are good work!

Submitted OSS Code server.js
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// server.js
// express modul
const express = require('express');
// nodemailer module
const nodemailer = require('nodemailer');
// path module, til pathing og filhåndtering
const path = require('path');
const app = express();

app.use(express.json());
app.use(express.static('public'));

// Hardcoded bruger til demostration af OTP
const validUser = {
    email: 'user@example.com', // insert email
    password: 'password123'
};

// Mulighed for et array af bruger, stadig hardcorded med mindre brug for at en data
// ved hjælp med værktøj som mongoose
// const users = [
//    {
//        email: 'user1@example.com',
//        password: 'password123',
//        currentOTP: null
//    },
//    {
//        email: 'user2@example.com',
//        password: 'password456',
//        currentOTP: null
//    }
// ];

// Email indstillinger til auth af google konto
const transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: 'user@example.com',    // insert Gmail
        pass: 'xxxx xxxx xxxx xxxx'        // insert Gmail konto app cus kode
    }
});

// Funktionen generateOTP() genererer en tilfældig 6-cifret engangskode (OTP) 
// som en streng.
// math.floor flat number uden decimal, math.random for random nr.
function generateOTP() {
    return Math.floor(100000 + Math.random() * 900000).toString();
}

// Håndterer GET-anmodning til roden ('/') ved at sende 'index.html'-filen fra mappen 
//'public' som svar.
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

// Håndterer POST-anmodning til '/login' og udtrækker 'email' og 'password' fra 
// anmodningens (html) body formular.
app.post('/login', async (req, res) => {
    const { email, password } = req.body;
    
    // Tjekker om den indtastede e-mail og adgangskode matcher den gyldige brugers 
    // oplysninger.  
// Hvis de matcher, genereres en engangskode (OTP) ved hjælp af generateOTP()-funktionen.
    if (email === validUser.email && password === validUser.password) {
        const otp = generateOTP();
        
        // Definerer mailindstillingerne for at sende OTP'en til brugeren, inklusive 
        // afsender, modtager, emne og beskedtekst.
        const mailOptions = {
            from: 'user@example.com', // mail
            to: email,
            subject: 'Login OTP',
            text: `Your OTP for login is: ${otp}`
        };
       
       // Forsøger at sende e-mailen med OTP ved hjælp af transporter.sendMail().  
        try {
            await transporter.sendMail(mailOptions);
// Hvis e-mailen sendes succesfuldt, gemmes OTP'en i validUser.currentOTP, 
// og der sendes et JSON-svar til klienten.
            validUser.currentOTP = otp;
            res.json({ message: 'OTP sent to your email' });
            // Håndterer fejl, der opstår under afsendelsen af e-mailen.  
            // Logger fejlen i konsollen og sender et JSON-svar med statuskode 
            // 500 til klienten, hvis afsendelsen mislykkes.
        } catch (error) {
            console.error('Email error:', error);
            res.status(500).json({ error: 'Failed to send OTP' });
        }
        // Hvis e-mail eller adgangskode ikke matcher den gyldige brugers oplysninger,  
// sendes et JSON-svar med statuskode 401, der angiver ugyldige loginoplysninger.
    } else {
        res.status(401).json({ error: 'Invalid credentials' });
    }
});

// Håndterer POST-anmodning til '/verify' og udtrækker 'email' og 
// 'otp' fra anmodningens body for at verificere OTP'en.
app.post('/verify', (req, res) => {
    const { email, otp } = req.body;
    // Tjekker om den indtastede e-mail og OTP matcher den gyldige brugers oplysninger.
    if (email === validUser.email && otp === validUser.currentOTP) {
// Hvis de er korrekte, nulstilles OTP'en, og der sendes et JSON-svar med 
// besked om, at login er vellykket. 
        validUser.currentOTP = null;
        res.json({ message: 'Login successful!' });
    } else {
    // Hvis OTP'en er forkert, sendes et JSON-svar med 
    // statuskode 401 og en fejlmeddelelse.
        res.status(401).json({ error: 'Invalid OTP' });
    }
});
// Starter serveren på port 3000 og logger en besked i konsollen for at 
// bekræfte, at serveren kører.
const PORT = 3000;
app.listen(PORT, () => {
    console.log(`Server running at http://localhost:${PORT}`);
});

The Excellent README.md Submitted with the Above

🔐 Two-Factor Authentication Login System 📚 About the Project This project demonstrates a login system with two-factor authentication (2FA), where an additional one-time password (OTP) is sent via email. The server verifies that the correct user uses the provided one-time code.

⚠️ Note: This code is public and available for everyone’s use. It is not a secure method for handling sensitive user data but serves as an example of how to implement email-based 2FA using OTP codes.

🎯 Project Context This project was developed for a Professional Bachelor’s Degree in Web Development. It is part of a submission covering:

🖇 JavaScript Frameworks 🔒 Data Security 📝 Project Requirements Each student was assigned one of the tasks below through electronic random selection. All tasks involve server-side and client-side programming.

💡 Guidelines: Use relevant technologies (libraries, frameworks, engines, etc.) introduced during the course. Additional technologies can be used if appropriate. Avoid unnecessary packages—only use what makes sense for the solution. Plain JavaScript is perfectly acceptable.

🛠 Task Description: Secure Login System with Role Management: ✅ Passwords must be securely hashed. 🔑 Role-based access control (RBAC) where only users with the correct role can access specific pages. For example, only admins can access system configuration. 👥 Implement at least three distinct user roles: Admin: Full access, including system configuration. Editor: Can write/edit content. Viewer: Read-only access.

🚀 Technologies Used: 🌐 Node.js 📬 Nodemailer (for sending OTP via email) 🔑 bcrypt (for password hashing) (Not implementet as of yet, but a surefire recommendation) 📦 Express.js (server-side framework) ⚡ JavaScript (ES6+)

💡 Getting Started

🔧 Installation To get this project up and running on your local machine, follow these steps:

Clone the Repository

Navigate to the folder where you want the project to be saved. Open your terminal and run the following command to clone the repository: git clone https://github.com/your-username/your-repo-name.git

After cloning, navigate into the project folder: cd your-repo-name Install Dependencies

The project uses Node.js and npm (Node Package Manager). Ensure you have them installed: Check Node.js: node -v Check npm: npm -v If you don’t have them, download and install Node.js.

To install all necessary dependencies, run: npm install This will install all required packages as listed in the package.json file. Set Up Environment Variables

To start the server, run: npm start The server will typically run on http://localhost:3000 (unless otherwise specified). Test the Application

Open your browser and go to http://localhost:3000. Try registering a user, logging in, and testing the two-factor authentication flow by checking your email for the OTP code.

✉️ Setting Up Gmail for Email OTP If you’re using Gmail to send OTP codes, you need to create an App Password because Gmail blocks less secure apps by default. Follow these steps:

🔒 Step 1: Enable 2-Step Verification on Your Google Account Go to your Google Account Security Settings. Under “Signing in to Google”, find “2-Step Verification” and click “Get Started”. Follow the prompts to enable 2-Step Verification for your account.

🔑 Step 2: Generate an App Password After enabling 2-Step Verification, return to the Security Settings. Under “Signing in to Google”, click “App passwords”. You might need to sign in again. Under “Select app”, choose “Mail”. Under “Select device”, choose “Other (Custom name)” and type a name like 2FA-Login-App. Click “Generate”. Google will display a 16-character password. Copy this password (without spaces).

✅ Features 🔐 Two-Factor Authentication: OTP sent via email. 🔒 Secure Password Storage: Passwords hashed with bcrypt. 👮 Role-Based Access Control: Admin, Editor, and Viewer roles. 💡 Clean and Simple UI for login and role management. ⚠️ Disclaimer This project is for educational purposes only. It is not production-ready and should not be used for handling real user data without additional security enhancements.

🤝 Contributing Contributions, issues, and feature requests are welcome!

📄 License This project is open-source.

Exercises

Exercise DS.9.0

The object of this exercise is clear. Given the code shown above, make a more generalized implementation of 2FA in the Exercise DS.8.0 that was given to you in the previous lesson.

  • Your solution should, of course, be worked into our normal MVC architecture
  • You must research whether there are alternatives to using gmail for the implementation
  • You must research whether phone based (text/sms) is an easily implementable alternative
  • Documentation of the two research questions above must be written into a section of your README.md