Continued my web security studies. I did some review before moving on with the rest of the PassportJS playlist. It has taken a few days but I am finally moving away from the exposure phase and more towards the comprehension phase of learning. I just have to keep going and eventually this will just be like everything I have learned before.
Not much else to report. A lot of refining with the express-session package notes. The documentation for the package is actually pretty messy. For a package that has over a million weekly downloads it is pretty crazy. I spent a lot of time adding overviews to each section of the API so that I can see all the options at a glance and click a link to the actual details that are further down on the page. The connect-mongo package’s docs were much more organized which I appreciated.
TLDR;
Okay, so here are the highlights of what I did:
- Backend -> Continued studying the concepts mentioned in the web security section. Reviewed my notes so far on Authentication, Authorization, HTTP cookies, Sessions, and the related
Node.jspackages.
Rough Notes – express-session Package
I tried to provide some overviews on all the properties and methods available with the package. I also reorganized it to present examples first. Maybe it is just my preference but I prefer seeing code snippets in how some code is used before seeing an explanation of it’s use. I like how Mozilla Docs does it.
Usage
Installation
This is a Node.js module available through the npm registry. Installation is done using the npm install command:
$ npm install express-session
Examples
View Counter
A simple example using express-session to store page views for a user.
var express = require("express");
var parseurl = require("parseurl");
var session = require("express-session");
var app = express();
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: true,
})
);
app.use(function (req, res, next) {
if (!req.session.views) {
req.session.views = {};
}
// get the url pathname
var pathname = parseurl(req).pathname;
// count the views
req.session.views[pathname] = (req.session.views[pathname] || 0) + 1;
next();
});
app.get("/foo", function (req, res, next) {
res.send("you viewed this page " + req.session.views["/foo"] + " times");
});
app.get("/bar", function (req, res, next) {
res.send("you viewed this page " + req.session.views["/bar"] + " times");
});
app.listen(3000);
User login
A simple example using express-session to keep a user log in session.
var escapeHtml = require("escape-html");
var express = require("express");
var session = require("express-session");
var app = express();
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: true,
})
);
// middleware to test if authenticated
function isAuthenticated(req, res, next) {
if (req.session.user) next();
else next("route");
}
app.get("/", isAuthenticated, function (req, res) {
// this is only called when there is an authentication user due to isAuthenticated
res.send(
"hello, " +
escapeHtml(req.session.user) +
"!" +
' <a href="/logout">Logout</a>'
);
});
app.get("/", function (req, res) {
res.send(
'<form action="/login" method="post">' +
'Username: <input name="user"><br>' +
'Password: <input name="pass" type="password"><br>' +
'<input type="submit" text="Login"></form>'
);
});
app.post(
"/login",
express.urlencoded({ extended: false }),
function (req, res) {
// login logic to validate req.body.user and req.body.pass
// would be implemented here. for this example any combo works
// regenerate the session, which is good practice to help
// guard against forms of session fixation
req.session.regenerate(function (err) {
if (err) next(err);
// store user information in session, typically a user id
req.session.user = req.body.user;
// save the session before redirection to ensure page
// load does not happen before session is saved
req.session.save(function (err) {
if (err) return next(err);
res.redirect("/");
});
});
}
);
app.get("/logout", function (req, res, next) {
// logout logic
// clear the user from the session object and save.
// this will ensure that re-using the old session id
// does not have a logged in user
req.session.user = null;
req.session.save(function (err) {
if (err) next(err);
// regenerate the session, which is good practice to help
// guard against forms of session fixation
req.session.regenerate(function (err) {
if (err) next(err);
res.redirect("/");
});
});
});
app.listen(3000);
Syntax / API
Example:
const express = require("express");
const session = require("express-session");
const app = express();
app.set("trust proxy", 1); // trust first proxy
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: true,
cookie: { secure: true },
})
);
session(options)
The session function takes one parameter which is an options object that is used to construct a session middleware. The options object has the following properties:
cookiecookie.domaincookie.expirescookie.httpOnlycookie.maxAgecookie.pathcookie.sameSitecookie.secure
genidnameproxyresaverollingsaveUninitializedsecret(REQUIRED)storeunset
Note Session data is not saved in the cookie itself, just the session ID. Session data is stored server-side.
Note: Since version 1.5.0, the cookie-parser middleware no longer needs to be used for this module to work. This module now directly reads and writes cookies on req/res. Using cookie-parser may result in issues if the secret is not the same between this module and cookie-parser.
Warning: The default server-side session storage (MemoryStore), is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing. That is why we have to use an external database to store the session data in a production environment. There is a long list of compatible Session store packages below. This list contains a lot of packages that span across the majority if not all of the popular databases used today.
options.cookie
Settings object for the session ID cookie. The default value is:
{
path: '/',
httpOnly: true,
secure: false,
maxAge: null
}
req Added Properties
Once the session middleware is set in our express app from app.use(session(options)) we can access the session data on all incoming requests from within our callbacks using the http.ClientRequest object (Commonly named req). The req object has the session property added through the express-session middleware call. The req.session object has custom properties that we can add as well as default properties like:
req.session.regenerate(callback)req.session.destroy(callback)req.session.reload(callback)req.session.save(callback)req.session.touch()req.session.idreq.session.cookiereq.session.cookie.maxAgereq.session.cookie.originalMaxAgereq.session.cookie.expires
req.sessionID
Session Store Implementation
Every session store must be an EventEmitter and implement specific methods. The following methods are the list of required, recommended, and optional.
- Required methods are ones that this module will always call on the store.
- Recommended methods are ones that this module will call on the store if available.
- Optional methods are ones this module does not call at all, but helps present uniform stores to users.
For an example implementation view the connect-redis repo:
store.all(callback)= Optionalstore.destroy(sid, callback)= Requiredstore.clear(callback)= Optionalstore.length(callback)= Optionalstore.get(sid, callback)= Requiredstore.set(sid, session, callback)= Requiredstore.touch(sid, session, callback)= Recommended
Compatible Session Stores
The following modules implement a session store that is compatible with this module.
aerospike-session-storeA session store using Aerospike.better-sqlite3-session-storeA session store based on better-sqlite3.cassandra-storeAn Apache Cassandra-based session store.cluster-storeA wrapper for using in-process / embedded stores – such as SQLite (via knex), leveldb, files, or memory – with node cluster (desirable for Raspberry Pi 2 and other multi-core embedded devices).connect-arangoAn ArangoDB-based session store.connect-azuretablesAn Azure Table Storage-based session store.connect-cloudant-storeAn IBM Cloudant-based session store.connect-couchbaseA couchbase-based session store.connect-datacacheAn IBM Bluemix Data Cache-based session store.@google-cloud/connect-datastoreA Google Cloud Datastore-based session store.connect-db2An IBM DB2-based session store built using ibm_db module.connect-dynamodbA DynamoDB-based session store.@google-cloud/connect-firestoreA Google Cloud Firestore-based session store.connect-hazelcastHazelcast session store for Connect and Express.connect-lokiA Loki.js-based session store.connect-lowdbA lowdb-based session store.connect-memcachedA memcached-based session store.connect-memjsA memcached-based session store using memjs as the memcached client.connect-mlA MarkLogic Server-based session store.connect-monetdbA MonetDB-based session store.connect-mongoA MongoDB-based session store.connect-mongodb-sessionLightweight MongoDB-based session store built and maintained by MongoDB.connect-mssql-v2A Microsoft SQL Server-based session store based on connect-mssql.connect-neo4jA Neo4j-based session store.connect-pg-simpleA PostgreSQL-based session store.connect-redisA Redis-based session store.connect-session-firebaseA session store based on the Firebase Realtime Databaseconnect-session-knexA session store using Knex.js, which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle.connect-session-sequelizeA session store using Sequelize.js, which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL.connect-sqlite3A SQLite3 session store modeled after the TJ’s connect-redis store.connect-typeormA TypeORM-based session store.couchdb-expressionA CouchDB-based session store.dynamodb-storeA DynamoDB-based session store.express-etcdAn etcd based session store.express-mysql-sessionA session store using native MySQL via the node-mysql module.express-nedb-sessionA NeDB-based session store.express-oracle-sessionA session store using native oracle via the node-oracledb module.express-session-cache-managerA store that implements cache-manager, which supports a variety of storage types.express-session-etcd3An etcd3 based session store.express-session-levelA LevelDB based session store.express-session-rsdbSession store based on Rocket-Store: A very simple, super fast and yet powerfull, flat file database.express-sessionsA session store supporting both MongoDB and Redis.firestore-storeA Firestore-based session store.fortune-sessionA Fortune.js based session store. Supports all backends supported by Fortune (MongoDB, Redis, Postgres, NeDB).hazelcast-storeA Hazelcast-based session store built on the Hazelcast Node Client.level-session-storeA LevelDB-based session store.lowdb-session-storeA lowdb-based session store.medea-session-storeA Medea-based session store.memorystoreA memory session store made for production.mssql-session-storeA SQL Server-based session store.nedb-session-storeAn alternate NeDB-based (either in-memory or file-persisted) session store.@quixo3/prisma-session-storeA session store for the Prisma Framework.restsessionStore sessions utilizing a RESTful APIsequelstore-connectA session store using Sequelize.js.session-file-storeA file system-based session store.session-pouchdb-storeSession store for PouchDB / CouchDB. Accepts embedded, custom, or remote PouchDB instance and realtime synchronization.session-rethinkdbA RethinkDB-based session store.@databunker/session-storeA Databunker-based encrypted session store.sessionstoreA session store that works with various databases.tch-nedb-sessionA file system session store based on NeDB.
Goal For Round 8 of the #100DaysofCode Challenge
This is my eighth round of the “#100daysofcode” challenge. I will be continuing my work from round five, six, and seven into round eight. I was working through the book “Cracking the Coding Interview” by Gayle Laakmann McDowell. My goal was to become more familiar with algorithms and data structures. This goal was derived from my goal to better understand operating systems and key programs that I use in the terminal regularly e.g. Git. This goal was in turn derived from my desire to better understand the fundamental tools used for coding outside of popular GUIs. This in turn was derived from my desire to be a better back-end developer.
I am currently putting a pause on the algorithm work to build some backend/full stack projects. I primarily want to improve my skills with the back-end from an implementation perspective. I have improved tremendously in terminal and CLI skills but I lost focus due to how abstract the algorithm concepts got. I wanted to work on things that were more tangible until I can get to a position where I could directly benefit from improving my algorithm skills and theoretical knowledge. So that’s the focus right now. Build my backend skills and prove my full stack capabilities by building some dope projects.
Again, I still have no idea if my path is correct but I am walking down this road anyways. Worst case scenario I learn a whole bunch of stuff that will help me out on my own personal projects. Best case scenario I actually become one of those unicorn developers that go on to start a billion dollar company… You never know LOL.