DEV Community 👩‍💻👨‍💻

Cover image for Express Hardening Cheatsheet
Amin
Amin

Posted on

Express Hardening Cheatsheet

X-Powered-By

npm install express
Enter fullscreen mode Exit fullscreen mode
import express from "express"

const server = express()

server.disable("x-powered-by")

server.get("/hello", (request, response) => {
  response.send("hello")
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Cross Origin Resource Sharing

npm install express cors
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import cors from "cors"

const server = express()

const allowedOrigins = [
  "yourdomain.com",
  "anotherdomain.com"
]

server.use(cors({
  origin: (origin, next) => {
    if (allowedOrigins.includes(origin)) {
      next(null, true)
    } else {
      next(new Error(`${origin} not allowed`))
    }
  }
}))

server.get("/hello", (request, response) => {
  response.send("hello")
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Security Headers

npm install express helmet
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import helmet from "helmet"

const server = express()

server.use(helmet())

server.get("/hello", (request, response) => {
  response.send("hello")
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Secrets

npm install express dotenv
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import dotenv from "dotenv"

dotenv.config()

const connect = (databaseCredentials) => {
  console.log(databaseCredentials)
  // TODO: connect to database
}

const server = express()

server.get("/hello", (request, response) => {
  const connection = connect(process.env.DATABASE_CREDENTIALS)

  response.send("hello")
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Secure Sessions

npm install express express-session
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import session from "express-session"

const server = express()

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: true,
  cookie: {
    secure: true,
    httpOnly: true,
    sameSite: true
  }
}))

server.get("/hello", (request, response) => {
  response.send("hello")
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Cross Site Request Forgery Protection

npm install express csurf express-session
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import csurf from "csurf"
import session from "express-session"

const server = express()

server.use(session({
  secret: process.env.SESSION_SECRET,
  name: "session",
  resave: false,
  saveUninitialized: true,
  cookie: {
    secure: true,
    httpOnly: true,
    sameSite: true
  }
}))

const csrfMiddleware = csurf({
  sessionKey: "session"
})

server.get("/form", csrfMiddleware, (request, response) => {
  response.set("Content-Type", "text/html").send(`
    <!DOCTYPE html>
    <form>
      <input type="email">
    </form>
  `)
})

server.get("/api/form", csrfMiddleware, (request, response) => {
  response.json({
    _csrf: request.csrfToken()
  })
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Parameters Pollution

npm install express body-parser hpp
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import bodyParser from "body-parser"
import hpp from "hpp"

const server = express()

server.use(bodyParser.urlencoded({
  extended: true
}))

server.use(hpp())

server.get("/hello", (request, response) => {
  response.json({
    name: request.query?.name ?? "unknown"
  })
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Body validation

npm install express zod
Enter fullscreen mode Exit fullscreen mode
import express from "express"
import bodyParser from "body-parser"
import z from "zod"

const server = express()

server.use(bodyParser.json())

server.post("/api/users", (request, response) => {
  try {
    const schema = z.object({
      email: z.string(),
      password: z.string(),
      confirmation: z.string()
    })

    const input = schema.parse(request.body)

    response.status(200).send("TODO: save the user")
  } catch (error) {
    response.status(400).send(error.message)
  }
})

server.listen(8000, () => {
  console.log("Server is listening")
})
Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Try wj-config for configuration instead of dotenv.

Collapse
 
aminnairi profile image
Amin Author

Hi José, thanks for sharing this package.

Looks like it is doing a lot more than just managing environment variables and I wanted to put a more lightweight alternative to dotenv in my article but this is not the goal and I wanted to use a battle-tested package to focus on the security side.

And I'm sure it will fit needs for those who are interested in this all-in-one configuration package.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Noted, no worries. As clarification, the advantage of this package is that works just as well in the browser, so you have one way to configure all your JavaScript. It now no longer matters if it is NodeJS or browser, it just works the same everywhere.

🌚 Life is too short to browse without dark mode