Why worry about Security?
Before starting to see about Strapi's Content-Types, before looking at Next.js' file and route structure, it's good to discuss Security.
A concern that usually is not followed up with due attention in certain teams, and that can cause a very high cost, when a project is put into production.
This article is another introductory article to the Next.js + Strapi stack, we will also cover TypeScript, Data Fetch, Layouts, CI / CD and Deploy, but first of all we will cover security.
Below we will discuss, the most common security errors in web applications and how to mitigate or fix them in our Strapi + Next.js application:
XSS / CRSF:
XSS or Cross Site Scripting, is a malicious technique to inject code into our application and circumvent security to hijack data or manipulate a user's session for example.
CRSF or Cross-site request forgery, is when someone uses a malicious technique to get through a request either via Postman or browser to reach our database, delete user data for example, steal session data (like credit card , addresses, etc.) among other things.
Click Jacking:
Do you know when you open pages that tend to trick the user into typing data and in the end they end up sending that data to people they want to use maliciously? Or that they may have malware or exploits and install them on the user's machine?
Common vulnerabilities in Rest APIS:
DOS & DDOS (Denial of Service): When a hacker wants to take down an API, application or website, he can fire bulk requests for that API or endpoint.
Exposure of Sensitive Information: When we expose sensitive user data, especially without encryption in our API. Ids, emails, addresses, payment information, etc.MIM (Man in the Middle) attacks: When a hacker tries to intercept client and server communication, with the intention of stealing data.
SQL Injection: Injection of code that changes the expected behavior of the API and the Database. Through an injection, a hacker is able to steal information, break the API, change its operation.
Insecure Direct Object References: When you expose an API with endpoints like
/ user / id / 30
, and a user tries to access an ID that does not compete with it, and succeeds, you are exposing
Direct References for insecure objects.
Common vulnerabilities in GraphQL APIS :
/ graphql? query = {__ schema {types {name, fields {name}}}}:
If your GraphQL API is public, only with a query like this, the user who uses it, can see the entire schema of your APIMalicious Queries: Hackers can mount malicious queries, whether to steal data, corrupt your database, or bring down your API / server
Brute-Force: To avoid problems with hackers trying to break the data in your GraphQL API, you can use plugins like GraphQL Rate Limit, which will limit how many times the vulnerable fields of your query can be executed in a time interval.
How to avoid all this?
On Strapi:
Understanding the Strapi Configuration file & its security: Strapi has rich documentation that shows us how to guarantee the security of the CMS:
It has configurations for XSS, P3P, Hsts, X-Frame-Options (Clickjacking), CORS (very useful to define which domains can access your application, which headers can be exposed),
IP (Can configure which IPS see or not your application)Credential Injection: Use a .env file, to avoid injecting credentials in the middle of your code
Validation: You can create a middleware to validate that your application data already exists and will not be duplicated, or you can also use a lib like Joi, to validate your API fields, but Strapi already has some native validations that you can define in your API models, only if you use MongoDB
Roles & Permissions: Ideally, you should create documentation for your API on which permissions and endpoints you will enable so that you don't end up making the mistake of allowing everything and offering risk to your API data
Policies: You can set your API's policies directly in Strapi's code through
./config/policies
for global Policies and./api/**/config/policies
for local endpoints. It is an extra layer of security for your Strapi application. To set policies with GraphQL, Strapi's documentation has a page dedicated to that.Data-Leak: You can pass a private: true parameter, within the parameter in your API model, to remove the value of being accessed by anyone. Click here to learn more
JWT: you can require the user to access sensitive endpoints of your application to be logged in and use JWT.
Exposure of Sensitive Information: Strapi allows to edit the controllers, which information can be accessed in the calls of the endpoints. You can delete certain fields and parameters from the results.
In GraphQL:
DOS (Denial of Service): You need to limit your queries. A malicious hacker, if discovered its GraphQL API, can mount a series of queries that can overload your server. This is a great article on the Apollo blog that teaches some cases of malicious queries and how to avoid them.
Setting Policies for Queries: You have to customize the Schema of your GraphQL API, setting the desired policies to have control of who or how to access what in your API
Unauthorized access: You need to disable the GraphQL Playground, which is already disabled in the production version of Strapi (you can disable it for other environments here), then your GraphQL endpoint is not maintained by a route but by middleware.
It is necessary to create a new middleware, which will check if the endpoint we want is / graphql and if the authenticated user is what we want:
module.exports = strapi => {
return {
initialize() {
strapi.app.use(async (ctx, next) => {
const handleErrors = (ctx, err = undefined, type) => {
if (ctx.request.graphql === null) {
return (ctx.request.graphql = strapi.errors[type](err));
}
return ctx[type](err);
};
// check if it's a graphql request
if (ctx.request.url === '/graphql' && ctx.request.method === 'POST') {
if (ctx.request && ctx.request.header && ctx.request.header.authorization) {
try {
// get token data
const { id } = await strapi.plugins[
'users-permissions'
].services.jwt.getToken(ctx);
if (id === undefined) {
throw new Error('Invalid token: Token did not contain required fields');
}
// check if the id match to the user you want
if (id !== 'my-user-id') {
return handleErrors(ctx, 'You are not authorized to access to the GraphQL API', 'unauthorized');
}
} catch (err) {
return handleErrors(ctx, err, 'unauthorized');
}
} else {
// if no authenticated, return an error
return handleErrors(ctx, 'You need to be authenticated to request GraphQL API', 'unauthorized');
}
}
await next();
});
}
};
};
To be authenticated you need to send a JWT in the header. See here in Strapi's authentication documentation how to do it.
In Next.js:
Validating fields: The validation of form fields is not only used to guide your users, but also to guarantee the integrity of the information transmitted from the client to the server. This prevents a series of malicious codes from being entered into our Services. The user can still try to manipulate the data by editing the HTML in DevTools, but that is another problem.
CRSF: Passing the parameter Content-Type: application / JSON, in our requests, forces our application not to use simple requests, and protects against attacks
XSS: This guide is very useful and shows some rules that it is good to follow when developing our front-end application so as not to have a headache afterward on security and XSS issues. This Next.js plugin also helps to implement XSS Protection, helping the browser to sanitize vulnerable areas of your application.
Security Headers & ClickJacking: Using X-Frame-Options: DENY or SAMEORIGIN, you prevent third parties from being able to run your Next.js application within a frame.
The next-secure-headers plugin helps you with that. In addition to implementing FrameGuard, it also implements XSS Protection, contentSecurityPolicy, nosniff, noopen, forceHTTPSRedirect, referrerPolicy, expectCT.JWT & Rolling Tokens: You can implement JWT, for the authentication of your App to guarantee the integrity of your API and access to it, this is a good tutorial that teaches this
More:
NextAuth.js: A plugin to help you with security in the authentication of your Next.js app
SSL:
One step before we publish our site for production is to set our domain and server to the HTTPS protocol. HTTPS protects our requests from being targeted by Man In the Middle attacks and is also crucial for SEO as it impacts Google's ranking.
Some ways to get free SSL certificates for your website are to use the service of:
APIS Caching:
Although it is not only a concern with security but also with performance, APIS caching can be recommended so that your site can work even in offline environments, but when it comes to dynamic data, it ends up being not recommended, only for data that is not. constantly change. This is a topic that requires an article just for him, but if you feel interested in knowing more about it I recommend reading the following articles:
- Web.dev: Cache API: Quick Guide
- Amazon API Gateway: API Caching
- Using Cloudflare with your API
- GraphQL Caching
Strapi's Safety Roadmap:
The Strapi team is planning some features that can help in future releases on security issues:
This is the Product Board link. In it, we see that the Strapi team plans features such as 2FA (Two-factor authentication), Rolling Token (JWT), SSO (Google, Twitter, Facebook, GitHub), among others that are already being tested: as Permissions and Rules per user and Permissions at field levels.
Checking tools:
There are some sites and tools on the web that test how secure our application is. Below are some of them:
Sentry: Sentry is a tool for monitoring web apps errors. It supports several technologies and platforms. It can be easily integrated with GraphQL, Strapi or Next.js. It has a free version for developers.
Sqreen: Sqreen is a webapps security monitoring platform. It can bring real-time data from potential exploits, protect you from attacks and malicious activities.
Strapi supports Sqreen.
First: create a Sqreen trial account
Second: set up your organization on the Sqreen dashboard
Third: set up Sqreen on Strapi
In Next.js you can also use Sqreen, but the configuration is a little more complicated
First: create a Sqreen trial account
Second: set up your organization on the Sqreen dashboard
The third :configure Next.js to use a Custom-Server
Configure Sqreen for Node.js
LGTM: LGTM is an open-source tool used by major players in the market, such as Google, Microsoft, Nasa, and Dell, which checks for vulnerabilities in your code through a repository on Github or BitBucket.
It has an automatic code review tool and is very powerful, it has alerts to warn you about problems in the code and also comparisons and history.SonarCloud: SonarQube is a very powerful tool that not only checks for bugs and vulnerabilities in your code but also some parameters like Code maintainability, Test Coverage, Codesmells, Code duplication, it analyzes your code and can stop a P / R or M / R on Github, GitLab, Azure DevOps or BitBucket if it does not reach the expected code quality. SonarCloud also has a plugin for IDES that checks in real-time
Mozilla Observatory: Mozilla tool that will help bring Insights about the security of your website.
DigiCert SSL Tools: It will check your SSL certificate data, show possible vulnerabilities, the Certificate Chain and the Server Configuration.
Qualys SSL Labs: Tool a little more complete than that of DigiCert.
Pen-test Tool: Website Vulnerability: Website that has SQL Injection checking, XSS, Inclusion of files, Execution of remote commands, however, it is paid.
Sucuri SiteChecker: Sucuri is well known in the world of web security. Detects if your site is blacklisted on Google, if it has unsafe links, among other security parameters
Well guys, thanks if you got here and had patience, the intention was to have given you a general idea of how to mitigate and solve various security and vulnerability problems in web applications with Next.js and Strapi, before we started using Stack, being that the concepts mentioned here can be used and verified in any web application not only with Node.js and JavaScript / TypeScript but with other languages and that use Rest APIs or GraphQL Apis. This is a very extensive subject that could yield several articles, but I tried to summarize in this one.
References:
Top comments (2)
I would suggest adding spyse.com/ next to the pentest-tool scanner as PT grabs info only from the website itself. And spyse shows the network side including leaked assets, security flaws, and potential breaches.
Great Post! Thanks!