Closed nperegrine closed 4 years ago
Hi, This is not a direct answer to your question, however, if by session you mean opaque tokens (random string as an access token), then just using that will not solve your concerns about token theft or CSRF.
At best, you cannot prevent token theft, all you can do is detect it and then take action. As per RFC 6749 (https://tools.ietf.org/html/rfc6749#section-10.4) using rotating refresh tokens is a great (and only reliable) method to detect token theft. Others use changes in IP address and device fingerprints as a proxy for token theft, but those lead to many false negatives/positives..
There is an article that talks about all the security considerations with sessions (including token theft and CSRF protection) and how you can solve them. Here is the link: https://supertokens.io/blog/all-you-need-to-know-about-user-session-security
I hope this helps.
Hi @nperegrine! :wave:
@rishabhpoddar Using the session
scheme means using a HTTP Only Secure Cookie configured with Same-Site. So it solves the issue of CSRF & XSS attacks.
Concerning your issue, ensure that you are sending the request from Nuxt using credentials: true
.
@RomainLanz thanks for the clarification. While same-site does solve CSRF for most cases, there may be a problem in using it (the point below is an edge use cases):
I'm not too sure about my opinion above, please correct me if I am wrong. That being said, I would still be most comfortable using anti-csrf tokens for CSRF protection.
@rishabhpoddar I'm not quite sure to have understood your first point.
Using Same-Site: LAX
is the way recommended by OWASP to avoid CSRF vulnerability. The primarily issue with this header is that IE11
do not support it.
Concerning your second point, this would be the result of a very bad API design. 😄 I believe it shouldn't not be used as example.
@RomainLanz Please allow me to rephrase my first point: same-site LAX, for website a.com will prevent its iframe on website b.com to work, assuming a.com is a service that needs to be embedded in other sites. That being said, this is a very nice case.
Also, I have edited my previous answer to remove the second point. Thanks!
Thank you very much @RomainLanz ... configuring credentials: true
with Axios and also setting credentials: true
in config/cors.js resolved the issue.
Thank you all for your assistance.
@rishabhpoddar I'm not quite sure to have understood your first point.
Using
Same-Site: LAX
is the way recommended by OWASP to avoid CSRF vulnerability. The primarily issue with this header is thatIE11
do not support it.Concerning your second point, this would be the result of a very bad API design. 😄 I believe it shouldn't not be used as example.
@RomainLanz please how can I set a cookie in AdonisJs as Same-site: LAX
to help prevent CSRF ? Here's how I'm creating my adonisjs cookie:
response.cookie('token', token, { secure: true, httpOnly: true, domain: 'domain.com', path: '/', sameSite: true, maxAge: 2592000 })
If I change sameSite: false
does that mean the same as Same-Site: LAX
or is there another way of doing this?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hello @RomainLanz @thetutlage ,
I keep getting the error "E_INVALID_SESSION: Invalid session" after I switch from "jwt" to "session" authentication scheme in api-only app.
Initially, I wanted to use the default "jwt" authentication scheme with my Nuxt front-end app, but due to security concerns about token theft and CSRF which are not handled by Nuxt.js at all, I decided I will switch back to basic "sessions" authentication.
Is it not possible to switch from "jwt" to "session" authentication with the api-only boilerplate? Or must I install the adonis-fullstack-app before I can use sessions? I have installed all the respective adonis sessions and shield modules but to no avail.
I don't know what I might be doing wrong and I think this may be a bug with AdonisJs
Steps to Reproduce
1.) Install adonis project using api-only flag 2.) Switch from "jwt" to "session" authentication scheme 3.) Make sure adonis "Session" and "Shield" modules are installed and configured properly 4.) Setup login and the register controller 5.) On successful login, when I try to access http://localhost:3333/v1/me to get the currently authenticated user, I get the error "E_INVALID_SESSION: Invalid session"
Here are my files
a.) auth.js
`/* @type {import('@adonisjs/framework/src/Env')} / const Env = use('Env')
module.exports = { authenticator: 'session',
session: { serializer: 'lucid', model: 'App/Models/User', scheme: 'session', uid: 'email', password: 'password' },
basic: { serializer: 'lucid', model: 'App/Models/User', scheme: 'basic', uid: 'email', password: 'password' }, jwt: { serializer: 'lucid', model: 'App/Models/User', scheme: 'jwt', uid: 'email', password: 'password', options: { secret: Env.get('APP_KEY') } },
api: { serializer: 'lucid', model: 'App/Models/User', scheme: 'api', uid: 'email', password: 'password' } }`
b.) session.js
`"use strict";
/* @type {import('@adonisjs/framework/src/Env')} / const Env = use("Env");
module.exports = {
driver: Env.get("SESSION_DRIVER", "cookie"),
cookieName: "keeb-session",
clearWithBrowser: true,
age: "2h",
cookie: { httpOnly: true, sameSite: false, path: "/" },
file: { location: "sessions" },
redis: { host: "127.0.0.1", port: 6379, password: null, db: 0, keyPrefix: "" } };`
c.) shield.js
`"use strict";
module.exports = {
csp: {
},
xss: { enabled: true, enableOnOldIE: false },
xframe: "DENY",
nosniff: true,
noopen: true,
csrf: { enable: false, methods: ["POST", "PUT", "DELETE"], filterUris: [], cookieOptions: { httpOnly: false, sameSite: true, path: "/", maxAge: 7200 } } };`
d.) start/app.js
`"use strict";
const providers = [ "@adonisjs/framework/providers/AppProvider", "@adonisjs/auth/providers/AuthProvider", "@adonisjs/bodyparser/providers/BodyParserProvider", "@adonisjs/cors/providers/CorsProvider", "@adonisjs/lucid/providers/LucidProvider", "@adonisjs/session/providers/SessionProvider", "adonis-lucid-polymorphic/providers/PolymorphicProvider", "adonis-bumblebee/providers/BumblebeeProvider", "@adonisjs/validator/providers/ValidatorProvider", "@adonisjs/mail/providers/MailProvider", "@adonisjs/framework/providers/ViewProvider", "@adonisjs/shield/providers/ShieldProvider" ];
const aceProviders = ["@adonisjs/lucid/providers/MigrationsProvider"];
const aliases = {};
const commands = [];
module.exports = { providers, aceProviders, aliases, commands };`
e.) start/kernel.js
`'use strict'
/* @type {import('@adonisjs/framework/src/Server')} / const Server = use('Server')
const globalMiddleware = [ 'Adonis/Middleware/BodyParser', 'Adonis/Middleware/Session', 'Adonis/Middleware/Shield', 'Adonis/Middleware/AuthInit', 'App/Middleware/ConvertEmptyStringsToNull', ]
const namedMiddleware = { auth: 'Adonis/Middleware/Auth', guest: 'Adonis/Middleware/AllowGuestOnly' }
const serverMiddleware = [ 'Adonis/Middleware/Static', 'Adonis/Middleware/Cors' ]
Server .registerGlobal(globalMiddleware) .registerNamed(namedMiddleware) .use(serverMiddleware)`
f.) Login controller
`"use strict";
class LoginController {` async login({ request, auth, response }) { const { email, password } = request.only(["email", "password"]);
return response.json({ status: "Login successful." }); }`
Package.json
{ "name": "adonis-api-app", "version": "4.1.0", "adonis-version": "4.1.0", "description": "Adonisjs boilerplate for API server with pre-configured JWT", "main": "index.js", "scripts": { "start": "node server.js", "test": "node ace test" }, "keywords": [ "adonisjs", "adonis-app" ], "author": "", "license": "UNLICENSED", "private": true, "dependencies": { "@adonisjs/ace": "^5.0.8", "@adonisjs/auth": "^3.1.0", "@adonisjs/bodyparser": "^2.0.5", "@adonisjs/cors": "^1.0.7", "@adonisjs/fold": "^4.0.9", "@adonisjs/framework": "^5.0.9", "@adonisjs/ignitor": "^2.0.8", "@adonisjs/lucid": "^6.1.3", "@adonisjs/mail": "^3.0.10", "@adonisjs/session": "^1.0.28", "@adonisjs/shield": "^1.0.8", "@adonisjs/validator": "^5.0.6", "@google-cloud/projectify": "^1.0.4", "adonis-bumblebee": "^2.1.0", "adonis-lucid-polymorphic": "^1.0.1", "aws-sdk": "^2.597.0", "axios": "^0.19.0", "device-detector-js": "^1.1.2", "formidable": "^1.2.1", "moment": "^2.24.0", "mysql": "^2.17.1", "nanoid": "^2.1.8", "pkgcloud": "^1.7.0", "sharp": "^0.23.4", "twilio": "^3.39.1" }, "devDependencies": { "babel-eslint": "^10.0.2", "eslint": "^6.8.0", "eslint-config-prettier": "^6.9.0", "eslint-loader": "^2.2.1", "eslint-plugin-prettier": "^3.1.2", "prettier": "^1.19.1" }, "autoload": { "App": "./app" } }
My experience with Adonis has been great. I personally don't like posting issues often but after a lot of research, I can't seem to figure out the cause of this error. I am currently rounding up with my project (nuxt.js frontend + adonisjs backend) and this is the main issue that's preventing us from going live.
Please any help or insight will be greatly appreciated 🙏🙏