Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Security basics

A site on the internet is probed by bots right away: they guess passwords, send odd data into forms, look for known vulnerabilities. A few simple measures close most typical attacks. Many of them have already appeared in the course; here they are collected together.

Protective headers: helmet

Browsers can protect visitors if the server asks them to via response headers. The helmet package sets a whole set of such headers in one line:

npm install helmet
// src/app.js
import helmet from 'helmet';
 
const app = express();
 
app.use(helmet());

Add it first. Open the developer tools, the Network tab, and pick any request: the response now has Content-Security-Policy, X-Content-Type-Options, Strict-Transport-Security and other headers, while the X-Powered-By: Express header, which gives the server away, is gone.

The Content-Security-Policy header blocks scripts and styles from other domains by default. If the blog loads, say, fonts from an external site, that domain has to be allowed in the helmet settings.

Rate limiting

A bot can try thousands of passwords a minute. The express-rate-limit package limits the number of requests from one IP address:

npm install express-rate-limit
// src/routes/auth.js
import { rateLimit } from 'express-rate-limit';
 
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  limit: 10,
  message: 'Too many login attempts, try again in 15 minutes',
});
 
router.post('/login', loginLimiter, authController.login);

One address can make 10 login attempts in 15 minutes; the eleventh gets a 429 response with this message. A general, softer limit can also cover the whole API: app.use('/api', apiLimiter).

Input validation

Anything that comes from the client — parameters, query string, body, headers, files — can be anything at all. The rules from earlier lessons:

ThreatProtection
Wrong or extra fieldsA Zod schema and safeParse()
SQL injection? marks in queries, not template strings
XSS in templatesPrinting with <%=, not <%-
Dangerous filesType filter, size limit, server-generated name
Password guessingbcrypt and rate limiting

Secure cookies

On a production server enable extra flags for the session cookie:

// src/app.js
app.use(session({
  secret: config.sessionSecret,
  resave: false,
  saveUninitialized: false,
  cookie: { httpOnly: true, secure: config.isProduction, sameSite: 'lax' },
}));

secure sends the cookie over HTTPS only, and sameSite: 'lax' stops other sites from submitting forms on behalf of a logged-in user.

Updates

Vulnerabilities are found in packages too. npm audit checks your dependencies against a database of known problems, and npm outdated shows outdated versions. Run them regularly.

Common mistake

Do not show visitors the error text and stack trace: res.status(500).send(error.stack) reveals file paths, package versions and pieces of code. Write the details to the log with console.error(), and answer the visitor with a general "Server error".

Thanks for reading!

Donate to the site — we work hard for you.