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.js
packages.
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:
cookie
cookie.domain
cookie.expires
cookie.httpOnly
cookie.maxAge
cookie.path
cookie.sameSite
cookie.secure
genid
name
proxy
resave
rolling
saveUninitialized
secret
(REQUIRED)store
unset
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.id
req.session.cookie
req.session.cookie.maxAge
req.session.cookie.originalMaxAge
req.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-store
A session store using Aerospike.better-sqlite3-session-store
A session store based on better-sqlite3.cassandra-store
An Apache Cassandra-based session store.cluster-store
A 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-arango
An ArangoDB-based session store.connect-azuretables
An Azure Table Storage-based session store.connect-cloudant-store
An IBM Cloudant-based session store.connect-couchbase
A couchbase-based session store.connect-datacache
An IBM Bluemix Data Cache-based session store.@google-cloud/connect-datastore
A Google Cloud Datastore-based session store.connect-db2
An IBM DB2-based session store built using ibm_db module.connect-dynamodb
A DynamoDB-based session store.@google-cloud/connect-firestore
A Google Cloud Firestore-based session store.connect-hazelcast
Hazelcast session store for Connect and Express.connect-loki
A Loki.js-based session store.connect-lowdb
A lowdb-based session store.connect-memcached
A memcached-based session store.connect-memjs
A memcached-based session store using memjs as the memcached client.connect-ml
A MarkLogic Server-based session store.connect-monetdb
A MonetDB-based session store.connect-mongo
A MongoDB-based session store.connect-mongodb-session
Lightweight MongoDB-based session store built and maintained by MongoDB.connect-mssql-v2
A Microsoft SQL Server-based session store based on connect-mssql.connect-neo4j
A Neo4j-based session store.connect-pg-simple
A PostgreSQL-based session store.connect-redis
A Redis-based session store.connect-session-firebase
A session store based on the Firebase Realtime Databaseconnect-session-knex
A session store using Knex.js, which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle.connect-session-sequelize
A session store using Sequelize.js, which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL.connect-sqlite3
A SQLite3 session store modeled after the TJ’s connect-redis store.connect-typeorm
A TypeORM-based session store.couchdb-expression
A CouchDB-based session store.dynamodb-store
A DynamoDB-based session store.express-etcd
An etcd based session store.express-mysql-session
A session store using native MySQL via the node-mysql module.express-nedb-session
A NeDB-based session store.express-oracle-session
A session store using native oracle via the node-oracledb module.express-session-cache-manager
A store that implements cache-manager, which supports a variety of storage types.express-session-etcd3
An etcd3 based session store.express-session-level
A LevelDB based session store.express-session-rsdb
Session store based on Rocket-Store: A very simple, super fast and yet powerfull, flat file database.express-sessions
A session store supporting both MongoDB and Redis.firestore-store
A Firestore-based session store.fortune-session
A Fortune.js based session store. Supports all backends supported by Fortune (MongoDB, Redis, Postgres, NeDB).hazelcast-store
A Hazelcast-based session store built on the Hazelcast Node Client.level-session-store
A LevelDB-based session store.lowdb-session-store
A lowdb-based session store.medea-session-store
A Medea-based session store.memorystore
A memory session store made for production.mssql-session-store
A SQL Server-based session store.nedb-session-store
An alternate NeDB-based (either in-memory or file-persisted) session store.@quixo3/prisma-session-store
A session store for the Prisma Framework.restsession
Store sessions utilizing a RESTful APIsequelstore-connect
A session store using Sequelize.js.session-file-store
A file system-based session store.session-pouchdb-store
Session store for PouchDB / CouchDB. Accepts embedded, custom, or remote PouchDB instance and realtime synchronization.session-rethinkdb
A RethinkDB-based session store.@databunker/session-store
A Databunker-based encrypted session store.sessionstore
A session store that works with various databases.tch-nedb-session
A 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.