-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0a06e40
Showing
9 changed files
with
5,970 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
.next | ||
yarn-error.log | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Nextjs CSRF POC (Proof of Concept) | ||
|
||
According to [wikipedia](https://en.wikipedia.org/wiki/Cross-site_request_forgery) | ||
|
||
> Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF (sometimes pronounced sea-surf) or XSRF, is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the web application trusts. | ||
Just a bare minimal implementation using csrf token with [nextjs](https://nextjs.org/) | ||
|
||
Module i used | ||
|
||
- https://github.com/pillarjs/csrf | ||
- https://github.com/maticzav/nookies | ||
- https://github.com/hoangvvo/next-connect | ||
|
||
There are some rules in this case | ||
|
||
- Csrf secret stored in `_csrf` cookie. | ||
- Csrf token stored in `x-xsrf-token` cookie, _latter to be used for XHR/API call_. | ||
- In this case i will use [axios](https://github.com/axios/axios) for calling api since the module has built action for carries `x-xsrf-token` automatically | ||
- Restriction only applied on `/api/*` path | ||
- Csrf token also available in `req.token` if you decide to put the token into `pageProps` by using `getServerSideProps` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/// <reference types="next" /> | ||
/// <reference types="next/types/global" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "next-csrf", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"license": "MIT", | ||
"scripts": { | ||
"dev": "next dev", | ||
"start": "next start", | ||
"build": "next build" | ||
}, | ||
"dependencies": { | ||
"axios": "^0.19.2", | ||
"csrf": "^3.1.0", | ||
"next": "^9.4.4", | ||
"next-connect": "^0.8.1", | ||
"nookies": "^2.3.2", | ||
"react": "^16.13.1", | ||
"react-dom": "^16.13.1" | ||
}, | ||
"devDependencies": { | ||
"@types/cookie-parser": "^1.4.2", | ||
"@types/csrf": "^1.3.2", | ||
"@types/node": "^14.0.14", | ||
"@types/react": "^16.9.41", | ||
"@types/react-dom": "^16.9.8", | ||
"typescript": "^3.9.6" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import withMiddleware from '../../util/withMiddleware' | ||
|
||
export default async (req, res) => { | ||
await withMiddleware(req, res) | ||
return res.json({ message: '@pedox' }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import axios from 'axios' | ||
import { GetServerSideProps } from 'next' | ||
import { useEffect, useState } from 'react' | ||
import withMiddleware from '../util/withMiddleware' | ||
export default ({ token }) => { | ||
const [name, setName] = useState('') | ||
useEffect(() => { | ||
const callApi = async () => { | ||
const { data } = await axios.get('/api/hello') | ||
setName(data.message) | ||
} | ||
callApi() | ||
}, [setName]) | ||
|
||
return ( | ||
<div className='main'> | ||
<h1>hello {name}</h1> | ||
<p> | ||
Direct access without x-xsrf-token header{' '} | ||
<a href='/api/hello' target='_blank' rel='noopener noreferrer'> | ||
/api/hello | ||
</a> | ||
</p> | ||
<pre> | ||
Check devtools for see request payload{'\n\n'} | ||
In case you want render csrf token to html page {'\n\n'}CSRF TOKEN:{' '} | ||
{token} | ||
</pre> | ||
<style jsx>{` | ||
.main { | ||
font-family: sans-serif; | ||
} | ||
`}</style> | ||
</div> | ||
) | ||
} | ||
|
||
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => { | ||
try { | ||
await withMiddleware(req, res) | ||
return { props: { token: (req as any).token } } | ||
} catch (e) { | ||
//... | ||
} | ||
return { props: { statusCode: 500 } } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es5", | ||
"lib": [ | ||
"dom", | ||
"dom.iterable", | ||
"esnext" | ||
], | ||
"allowJs": true, | ||
"skipLibCheck": true, | ||
"strict": false, | ||
"forceConsistentCasingInFileNames": true, | ||
"noEmit": true, | ||
"esModuleInterop": true, | ||
"module": "esnext", | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
"isolatedModules": true, | ||
"jsx": "preserve" | ||
}, | ||
"exclude": [ | ||
"node_modules" | ||
], | ||
"include": [ | ||
"next-env.d.ts", | ||
"**/*.ts", | ||
"**/*.tsx" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import Tokens from 'csrf' | ||
import nc from 'next-connect' | ||
import { parseCookies } from 'nookies' | ||
|
||
const tokens = new Tokens() | ||
|
||
const withMiddleware = async (req, res) => { | ||
const handler = nc().use((req, res, next) => { | ||
const cookies = parseCookies({ req }) | ||
|
||
if (new RegExp('^/api', 'i').test(req.url)) { | ||
if (!tokens.verify(cookies._csrf || '', req.headers['x-xsrf-token'])) { | ||
return res.status(403).json({ message: 'csrf_token_invalid' }) | ||
} | ||
} | ||
|
||
const secret = cookies._csrf || tokens.secretSync() | ||
|
||
req.token = tokens.create(secret) | ||
res.setHeader('Set-Cookie', [ | ||
`_csrf=${secret}; path=/`, | ||
`XSRF-TOKEN=${tokens.create(secret)}; path=/`, | ||
]) | ||
next() | ||
}) | ||
|
||
return await handler.apply(req, res) | ||
} | ||
|
||
export default withMiddleware |
Oops, something went wrong.