1
0
mirror of https://github.com/sasjs/server.git synced 2026-01-15 18:00:05 +00:00

Merge pull request #155 from sasjs/api-access-via-session-authentication

fix: added CSRF check for granting access via session authentication
This commit is contained in:
Allan Bowe
2022-04-30 21:44:35 +03:00
committed by GitHub
8 changed files with 37 additions and 16 deletions

14
api/package-lock.json generated
View File

@@ -17,6 +17,7 @@
"csurf": "^1.11.0", "csurf": "^1.11.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-session": "^1.17.2", "express-session": "^1.17.2",
"helmet": "^5.0.2",
"joi": "^17.4.2", "joi": "^17.4.2",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.12", "mongoose": "^6.0.12",
@@ -4817,6 +4818,14 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/helmet": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-5.0.2.tgz",
"integrity": "sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg==",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/html-encoding-sniffer": { "node_modules/html-encoding-sniffer": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -14126,6 +14135,11 @@
"integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
"dev": true "dev": true
}, },
"helmet": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-5.0.2.tgz",
"integrity": "sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg=="
},
"html-encoding-sniffer": { "html-encoding-sniffer": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",

View File

@@ -56,6 +56,7 @@
"csurf": "^1.11.0", "csurf": "^1.11.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-session": "^1.17.2", "express-session": "^1.17.2",
"helmet": "^5.0.2",
"joi": "^17.4.2", "joi": "^17.4.2",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.12", "mongoose": "^6.0.12",

View File

@@ -7,6 +7,7 @@ import morgan from 'morgan'
import cookieParser from 'cookie-parser' import cookieParser from 'cookie-parser'
import dotenv from 'dotenv' import dotenv from 'dotenv'
import cors from 'cors' import cors from 'cors'
import helmet from 'helmet'
import { import {
connectDB, connectDB,
@@ -37,6 +38,11 @@ export const cookieOptions = {
***********************************/ ***********************************/
export const csrfProtection = csrf({ cookie: cookieOptions }) export const csrfProtection = csrf({ cookie: cookieOptions })
/***********************************
* Handle security and origin *
***********************************/
app.use(helmet())
/*********************************** /***********************************
* Enabling CORS * * Enabling CORS *
***********************************/ ***********************************/

View File

@@ -1,11 +1,16 @@
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import { csrfProtection } from '../app'
import { verifyTokenInDB } from '../utils' import { verifyTokenInDB } from '../utils'
export const authenticateAccessToken = (req: any, res: any, next: any) => { export const authenticateAccessToken = (req: any, res: any, next: any) => {
// if request is coming from web and has valid session
// we can validate the request and check for CSRF Token
if (req.session?.loggedIn) { if (req.session?.loggedIn) {
req.user = req.session.user req.user = req.session.user
return next()
return csrfProtection(req, res, next)
} }
authenticateToken( authenticateToken(
req, req,
res, res,

View File

@@ -4,6 +4,8 @@ import webRouter from './web'
const router = express.Router() const router = express.Router()
router.use('/', csrfProtection, webRouter) router.use(csrfProtection)
router.use('/', webRouter)
export default router export default router

View File

@@ -6,19 +6,17 @@ import { getWebBuildFolderPath, loginWebValidation } from '../../utils'
const webRouter = express.Router() const webRouter = express.Router()
webRouter.get('/', async (_, res) => { webRouter.get('/', async (req, res) => {
const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html') const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html')
if (await fileExists(indexHtmlPath)) return res.sendFile(indexHtmlPath) if (await fileExists(indexHtmlPath)) {
res.cookie('XSRF-TOKEN', req.csrfToken())
return res.sendFile(indexHtmlPath)
}
return res.send('Web Build is not present') return res.send('Web Build is not present')
}) })
webRouter.get('/form', function (req, res) {
// pass the csrfToken to the view
res.send({ csrfToken: req.csrfToken() })
})
webRouter.post('/login', async (req, res) => { webRouter.post('/login', async (req, res) => {
const { error, value: body } = loginWebValidation(req.body) const { error, value: body } = loginWebValidation(req.body)
if (error) return res.status(400).send(error.details[0].message) if (error) return res.status(400).send(error.details[0].message)

View File

@@ -10,13 +10,7 @@ const getAuthCode = async (credentials: any) =>
axios.post('/SASjsApi/auth/authorize', credentials).then((res) => res.data) axios.post('/SASjsApi/auth/authorize', credentials).then((res) => res.data)
const login = async (payload: { username: string; password: string }) => const login = async (payload: { username: string; password: string }) =>
axios.get('/form').then((res1) => axios.post('/login', payload).then((res) => res.data)
axios
.post('/login', payload, {
headers: { 'csrf-token': res1.data.csrfToken }
})
.then((res2) => res2.data)
)
const Login = ({ getCodeOnly }: any) => { const Login = ({ getCodeOnly }: any) => {
const location = useLocation() const location = useLocation()

View File

@@ -52,6 +52,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
}) })
.catch(() => { .catch(() => {
setLoggedIn(false) setLoggedIn(false)
axios.get('/') // get CSRF TOKEN
}) })
}, []) }, [])