Security
Security is an important aspect of all modern web applications. Implementing good security practices help prevent and mitigate various security threats and keep the user's data safe. The checklist below includes the common recommendations and sanity checks that will greatly improve security of your web applications.
General rules
Use encrypted protocols everywhere (HTTPS for web traffic, WSS for secure socket connection)
Don’t build custom authentication system yourself, use tried and tested libraries instead
Keep your dependencies up-to-date to prevent zero-day vulnerabilities
Exclude admin and private URLs from indexing and crawling (using robots.txt)
Don’t use iterable URLs (e.g. prefer
/users/[guid]
or/users/[handle]
instead of/users/[incremented-integer]
)Remove unused functionality instead of hiding it (with
display: none
, for instance)Use DDOS mitigation via a global caching proxy service like CloudFlare
For apps containing sensitive data, consider implementing auto session termination after a period of inactivity or require addition password check for destructive actions
Set
Cache-Control: no-store, max-age=0
for non-public/non-static content to make sure that the sensitive user-specific data doesn’t remain cached on disk after a logoutAdd subresource integrity checks if loading your JavaScript libraries from a third party CDN
Server secrets
Don’t hardcode API keys and tokens, store them in the
.env
file insteadDon’t commit
.env
file to the repository. Alternatively, f you want everyone with access to the repo have access to all the secrets, you can encrypt & version.env
file using git-cryptDon’t expose secret tokens from
.env
file to the client (make sure that you only access them in the server code, e.g. inside React server components orgetServerSideProps
)
Client secrets
Store session IDs and auth tokens in
Secure
HttpOnly
cookies, notlocalStorage
orsessionStorage
(also SameSite=Lax)Scope cookies to a domain (and a path, if applicable)
User input
Sanitize all user input, especially the values that will be passed to
dangerouslySetInnerHTML
to prevent XSS attacksAlways use whitelisting over blacklisting, aka list values that are allowed instead of listing values that aren’t
Use CAPTCHAs on sign-in and sign-up forms to prevent password enumeration
iFrames
Don’t use iFrames unless absolutely necessary (e.g. for third-party integrations)
Add
sandbox
attribute to enable extra set of restrictions on the iFrame contentDisable iFrame embedding to prevent click-jacking attacks with
X-Frame-Options
header:
Security headers
Use https://securityheaders.com/ to verify your security headers configuration
Use strong Content Security Policy headers (CSP) to mitigate XSS and data injection attacks
It’s better to start with the most restrictive settings, and start loosening them as needed (e.g. allowing unsafe-inline styles when using styled components or whitelisting more domains when using 3rd party integrations)
Disable access to browser features and APIs that aren’t used:
⚠️ Feature-Policy
header is being renamed to Permission-Policy
, so in the future only the latter will be used.
Use HSTS header to block all attempts to downgrade HTTPS to HTTP (or WSS to WS)
Enable X-XSS-Protection mode to mitigate XSS attacks
Github
Disable forking for the repository
Restrict & control access
Protect production branch - prevent force push & deletion, require signed commits, require PR approval from code owners before merging
Use minimally scoped credentials for running Github Actions
Use Github Secrets for storing environment variables for Github Actions
Don't reference values in Github Actions that can be set by users (e.g. PR title and body)
Last updated