NML Says

IT Infrastructure 2 - Security

References for this Part

Wladston Ferreira Filho, Computer Science Distilled: Learn The Art Of Solving Computational Problems code.energy, 2017

https://www.geeksforgeeks.org/computer-security-overview/

https://en.wikipedia.org/wiki/Cryptography

Model Solution Previous Lesson

Example 1. routes/users.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
const express = require('express');
const control = require('../controllers/controllers.js');

const router = express.Router();

/* get registration form */
router.get('/register', function(req, res, next) {
    res.render('register', {
        title: 'Register Please'
    });
});

/* post registration data from form */
router.post('/register', control.postRegistration, function(req, res, next) {
    res.render('login', {
        title: 'Login Please'
    });
});

/* get login form */
router.get('/login', function(req, res, next) {
    res.render('login', {
        title: 'Login Please'
  });
});

/* post login data from form */
router.post('/login', control.verifyLogin, function(req, res, next) {
    res.render('index', {
        title: 'Welcome',
        user: res.locals.user.email,
        message: 'has successfully logged in'
    });
});

module.exports = router;
Example 2. controllers/controllers.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
/* controllers.js */

const bcrypt = require('bcryptjs');
const models = require('../models/dbHandlers');

module.exports = {
    getQuotes: async function(req, res, next) {
        try {
            await models.selectQuotes(req, res);
            next();
        } catch(err) {
            res.status(500).json({message: err.message});
        }
    },

    isAdmin: async function(req, res, next) {
        try {
            if (res.locals.authorized && res.locals.profile == SU) 
                next();
            else
                throw new Error('You must be a logged in admin');
        } catch(err) {
            res.status(500).json({message: err.message});
        }
    }, 

    isAuth: async function(req, res, next) {
        try {
            next();
        } catch(err) {
            res.status(500).json({message: err.message});
        }
    },

    postQuote: async function(req, res, next) {
        try {
            next();
        } catch(err) {
            res.status(500).json({message: err.message});
        }
    },

    postRegistration: async function(req, res, next) {
        try {
            if (
                req.body.email === '' ||
                req.body.password === '' ||
                req.body.passwordrep === '' ||
                req.body.bio === '' 
            ) {
                throw new Error('All fields must have content');
            }
            if (req.body.password != req.body.passwordrep)
                throw new Error('Non matching passwords');
            let hash = await bcrypt.hash(req.body.password, parseInt(process.env.ROUNDS));
            res.locals.hash = hash;
            await models.insertUser(req, res);
            next();
        } catch(err) {
            res.status(500).json({message: err.message});
        }
    },

    verifyLogin: async function(req, res, next) {
        try {
            if (req.body.email === '' || req.body.password === '') {
                throw new Error('Missing credentials');
            }
            await models.getUser(req, res);
            let rc = await bcrypt.compare(req.body.password, '' + res.locals.user.password);
            if (!rc)
                throw new Error('Error in credentials');
            // create token for remembering login
            next();
        } catch(err) {
            res.status(500).json({message: err.message});
        }
    }

}
Example 3. models/dbHandlers.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
const models = require('./dbConnectionHandler');

module.exports = {
    getUser: async function (req, res) {
        try {
            let dbh = await models.connect();
            let sql = 'select * from user where email = ?';
            let row = await dbh.query(sql, [req.body.email]);
            if (!row)
                throw new Error('Error in credentials');
            res.locals.user = row[0];
        } catch (err) {
            throw new Error(err.message);
        }
    },

    insertUser: async function(req, res) {
        try {
            const dbh = await models.connect();
            let sql = 'insert into user (email, password, bio) values(?, ?, ?)';
            await dbh.query(sql, [req.body.email, res.locals.hash, req.body.bio]);
        } catch (err) {
            throw new Error(err.message);
        }
    },

    selectQuotes: async function(req, res) {
        try {
            const dbh = await models.connect();
            let sql = 'select * from quote';
            let rows = await dbh.query(sql);
            res.locals.quotes = rows;
        } catch (err) {
            throw new Error('db quote read err');
        }
    }
}

Security

Computer Security - Overview

Re https://www.geeksforgeeks.org/computer-security-overview/:

Computer security refers to protecting and securing computers and their related data, networks, software, hardware from unauthorized access, misuse, theft, information loss, and other security issues. The Internet has made our lives easier and has provided us with lots of advantages but it has also put our system’s security at risk of being infected by a virus, of being hacked, information theft, damage to the system, and much more.

In the good old days, protecting your computers, including the data on the computers, was easy, well, easier. The computers were locked away in computer centers, the doors were locked, only authorized staff had access, and if there were networks, they were separated from public networks.

Security issues were handled by backing up data, and keeping the backups geographically separated from the hard disks they copied. In addition core hardware elements were doubled to cater for malfunction, acts of nature, theft, etc.

Nowadays devices are ubiquitous, ie spread out and available everywhere. Computing power is in the hands of the user. The data is available both centrally, as back then, and locally. Data travels back and forth via public networks, and consequently the sensitive spots, the places where accidents may happen, have mulitplied exponentially.

What we saw above about redundancies in hardware, and decentrally kept backups, must still be done. But all the decentrally placed devices in user hands must follow the same regime. A stolen laptop, or a broken one, can easily be replaced, but the data from it cannot be bought in a store. So the old regime of backing up data must be multiplied to each device holding stored data.

Data is data that cannot be bought in a software shop. It is the data we generate and maintain for running our operations, but it is also the software that we develop ourselves for our own use.

In the old days we copied the operational data from one mainframe hard drive to another, and drove it across the company campus to lock it away in a vault in an office several hundred meters away.

In the advanced present days, we move data around to remote storage by means of the internet. A big step forward, but not without its risks. The internet is a mixture of publicly accessible networks, and locally accessible company internal networks. On the public networks we have come to know that the evil eye is watching our every step. Even internally, there may be the disgruntled colleague who for some reason want to steal a secret, or in other ways harm us.

Data Security

The are five cornerstones of modern data security, they are:

Confidentiality
When or if we need to restict knowledge of certain data to a limited target group, the technology must make it possible.
Integrity
The software involved must be able to substantiate that data has not been interfered with while in transit from the source to the intended target.
Authenticity
We must be able to ascertain that the stated source is actually the source.
Non Repudiation
The source of the data must not be able to deny being the source.
Availability
The information in question must be available to its proper users.

Many sources include authenticity and non repudiation as integral parts of integrity.

We have software that handles all cornerstones of moderne data security, but before diving into specifics we shall discuss two central topics of security cryptography, and cryptographic hash functions.

Cryptography

Re https://en.wikipedia.org/wiki/Cryptography modern cryptography can be describe under the following headings:

  • Symmetric-key cryptography
  • Public-key cryptography
  • Cryptographic hash functions
  • Cryptanalysis
  • Cryptographic primitives
  • Cryptosystems
  • Lightweight cryptography

Cryptography is an endeavour that achieves confidentiality as required by the first of the five cornerstones of modern data security as seen above.

The first two points describe two fundamentally different ways of taking some plaintext and by means of a key (some string) manipulating it into incomprehensible ciphertext.

There is basically no qualitative difference between cryptotext produced by the two ways of encryption.

In symmetric cryptography the two communicating parties must have the same key handy. That key is used to encrypt the plaintext into ciphertext, and the same key is needed to decrypt the ciphertext back into comprehensible plaintext. There is a serious problem involved in the exchange of the keys in symmetric cryptography. This is difficult to do electronically via the internet.

Public-key cryptography, aka asymmetric cryptography, has solved that problem. Here the communicating parties each generate two keys, a key-pair consisting of a public key, and a private key, and publish their public keys to whoever is interested. There are key servers where you may look up public keys of others. The private key is kept absolutely private. The system ensures that a plaintext encrypted with with some recipients public key, can only be decrypted with that recipients private key. For details refer to Chapter 2 of our security module, or, more or less equivalently to Chapter 4 of our cloud computing module.

Public-key cryptosystems also assures cornerstones 2, 3, and 4 of the five cornerstones of modern data security as seen above.

The sender of a message may sign the message with their private key. The system then assures that the recipient may verify the signature with the public key of the sender. Positive verification means that the message can only come from the matching private key.

Cryptographic Hash Functions

https://en.wikipedia.org/wiki/Cryptography#Cryptographic_hash_functions says that

Cryptographic hash functions are functions that take a variable-length input and return a fixed-length output …

The fixed length output from a CHF is called a message digest or, colloquially, a hash. Message digests are used for fingerprinting files to be transmitted. In many, most(?) cases we do not need to encrypt texts before transmitting them across the internet. Programs for installation is a good example. We do need, however, to make the recipient capable of verifying the authenticity of the received file. This can be done by hashing the file, and verifying that the message digest is the same as the published message digest of the file.

Hashes are also used for passwords. The reason they are preferred for passwords is that if they were encrypted we would need another password, a key, to verify it, and using hashes we can verify directly. The user enters his password, the application hashes that, and compares it to the stored hash of the user. Todays exercise solution in functions postRegistration and verifyLogin exemplify that.

Exercises

Exercise ITI.2.0

In verifyLogin there’s a comment: // create token for remembering login.

Todays exercise is using the npm module jsonwebtoken to achieve that.

A token must be created and returned to the user. The user should save it in a cookie or the browsers localStorage and then put it into the header of every HTTP package sending a request that requires login. This effort requires individual javascript in the login page.