Skip to main content

Web app development security best practices

Security
Concept

Overview

This document contains information regarding security best practices for developing web apps.

Authentication

Use a well-audited authentication service and client side ICP libraries

Security concern

Implementing user authentication and canister calls yourself in your web app is error prone and risky. For example, if canister calls are implemented from scratch, there may be bugs around signature creation or verification.

Recommendation

  • Consider using e.g. Internet Identity for authentication, use agent-js for making canister calls, and the auth-client for interacting with internet identity from your dapp.

  • It is of course also an option to consider alternative authentication frameworks on ICP for authentication.

Set an appropriate session timeout

Security concern

Currently, Internet Identity issues delegations with an expiry time. This expiry time can be set in the auth-client. After a delegation expires, the user has to re-authenticate. Setting a good value is a trade-off between security and usability.

Recommendation

See the OWASP recommendations. A timeout of 30 min should be set for security sensitive applications.

The auth-client supports idle timeouts. More details available here.

Don’t use fetchRootKey in agent-js in production

Security concern

agent.fetchRootKey() can be used in agent-js to fetch the root subnet threshold public key from a status call in test environments. This key is used to verify threshold signatures on certified data received through canister update calls. Using this method in a production web app gives an attacker the option to supply their own public key, invalidating all authenticity guarantees of update responses.

Recommendation

Never use agent.fetchRootKey() in production builds, only in test builds. Not calling this method will result in the hard coded root subnet public key of the mainnet being used for signature verification, which is the desired behavior in production.

Nonspecific to the Internet Computer

The best practices in this section are very general and not specific to the Internet Computer. This list is by no means complete and only lists a few very specific concerns that have led to issues in the past.

Don’t load JavaScript (and other assets) from untrusted domains

Security concern

Loading untrusted JavaScript from domains other than <canister-id>.icp0.io means you completely trust that domain. Also, assets loaded from these domains (incl. <canister-id>.raw.icp0.io) will not use asset certification.

If they deliver malicious JavaScript they can take over the web app/account by e.g. reading the private key managed by agent-js from LocalStorage.

Note that also loading other assets such as CSS from untrusted domains is a security risk, see e.g. here.

Recommendation

  • Loading JavaScript and other assets from other origins should be avoided. Especially for security critical applications, you can’t assume other domains to be trustworthy.

  • Make sure all the content delivered to the browser is served and certified by the canister using asset certification. This holds in particular for any JavaScript, but also for fonts, CSS, etc.

  • Use a content security policy to prevent scripts and other content from other origins to be loaded at all. See also define security headers including a content security policy (CSP).