Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Critical Security Flaw - Mongoose Model inside Webtoken #8

Closed
Mydayyy opened this issue Oct 2, 2017 · 1 comment · Fixed by #9
Closed

Critical Security Flaw - Mongoose Model inside Webtoken #8

Mydayyy opened this issue Oct 2, 2017 · 1 comment · Fixed by #9

Comments

@Mydayyy
Copy link
Contributor

Mydayyy commented Oct 2, 2017

Hi,

I noticed that you do have your full mongoose model inside the generated json webtoken. This is a huge security flaw, as a json webtoken is only signed but not encrypted, meaning that everyone who can retrieve a token from a user ( e.g sniffing ) is able to obtain the users cleartext password, even from expired tokens.

https://github.com/scotch-io/node-token-authentication/blob/master/server.js#L81

Please consider fixing this asap

~Mydayyy

Edit: I got asked to go a little more indepth about the underlying security issue here.

So basically, take a look at the line https://github.com/scotch-io/node-token-authentication/blob/master/server.js#L81

You see that the token gets created with jwt.sign(user, app.get('sup erSecret'), { expiresIn: 86400 // expires in 24 hours }). First argument, the user, is passed by mongodb as a response to the findOne query. This object contains all model data. Now, that user object is put into the JWT as a payload.

A JsonWebToken is signed but not encrypted, that means while we can verify that the content has not changed, it is still public for everyone. If you now receive a token by the API it contains all user information, including the cleartext password.

See the following webtoken for example ( which is returned by this API ):

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyIkX18iOnsic3RyaWN0TW9kZSI6dHJ1ZSwic2VsZWN0ZWQiOnt9LCJnZXR0ZXJzIjp7fSwiX2lkIjoiNTljZTRhNTUyZDQwODQ2YzBiOTM4MDg1Iiwid2FzUG9wdWxhdGVkIjpmYWxzZSwiYWN0aXZlUGF0aHMiOnsicGF0aHMiOnsiX192IjoiaW5pdCIsImFkbWluIjoiaW5pdCIsInBhc3N3b3JkIjoiaW5pdCIsIm5hbWUiOiJpbml0IiwiX2lkIjoiaW5pdCJ9LCJzdGF0ZXMiOnsiaWdub3JlIjp7fSwiZGVmYXVsdCI6e30sImluaXQiOnsiX192Ijp0cnVlLCJhZG1pbiI6dHJ1ZSwicGFzc3dvcmQiOnRydWUsIm5hbWUiOnRydWUsIl9pZCI6dHJ1ZX0sIm1vZGlmeSI6e30sInJlcXVpcmUiOnt9fSwic3RhdGVOYW1lcyI6WyJyZXF1aXJlIiwibW9kaWZ5IiwiaW5pdCIsImRlZmF1bHQiLCJpZ25vcmUiXX0sInBhdGhzVG9TY29wZXMiOnt9LCJlbWl0dGVyIjp7ImRvbWFpbiI6bnVsbCwiX2V2ZW50cyI6e30sIl9ldmVudHNDb3VudCI6MCwiX21heExpc3RlbmVycyI6MH19LCJpc05ldyI6ZmFsc2UsIl9kb2MiOnsiX192IjowLCJhZG1pbiI6dHJ1ZSwicGFzc3dvcmQiOiJwYXNzd29yZCIsIm5hbWUiOiJOaWNrIENlcm1pbmFyYSIsIl9pZCI6IjU5Y2U0YTU1MmQ0MDg0NmMwYjkzODA4NSJ9LCIkaW5pdCI6dHJ1ZSwiaWF0IjoxNTA2NjkxNzIyLCJleHAiOjE1MDY3NzgxMjJ9.WFZU_FwYzglN0vagVvBn4NYEaOS2tmKbUjrDUyhp8fQ

Go to https://jwt.io/ and select Debugger in the navigation panel. Now paste that token there. It will display the content which is the following:

  "$__": {
    "strictMode": true,
    "selected": {},
    "getters": {},
    "_id": "59ce4a552d40846c0b938085",
    "wasPopulated": false,
    "activePaths": {
      "paths": {
        "__v": "init",
        "admin": "init",
        "password": "init",
        "name": "init",
        "_id": "init"
      },
      "states": {
        "ignore": {},
        "default": {},
        "init": {
          "__v": true,
          "admin": true,
          "password": true,
          "name": true,
          "_id": true
        },
        "modify": {},
        "require": {}
      },
      "stateNames": [
        "require",
        "modify",
        "init",
        "default",
        "ignore"
      ]
    },                 
    "pathsToScopes": {},
    "emitter": {
      "domain": null,
      "_events": {},
      "_eventsCount": 0,
      "_maxListeners": 0
    }
  },
  "isNew": false,
  "_doc": {
    "__v": 0,{
  "$__": {
    "strictMode": true,
    "selected": {},
    "getters": {},
    "_id": "59ce4a552d40846c0b938085",
    "wasPopulated": false,
    "activePaths": {
      "paths": {
        "__v": "init",
        "admin": "init",
        "password": "init",
        "name": "init",
        "_id": "init"
      },
      "states": {
        "ignore": {},
        "default": {},
        "init": {
          "__v": true,
          "admin": true,
          "password": true,
          "name": true,
          "_id": true
        },
        "modify": {},
        "require": {}
      },
      "stateNames": [
        "require",
        "modify",
        "init",
        "default",
        "ignore"
      ]
    },
    "pathsToScopes": {},
    "emitter": {
      "domain": null,
      "_events": {},
      "_eventsCount": 0,
      "_maxListeners": 0
    }
  },
  "isNew": false,
  "_doc": {
    "__v": 0,
    "admin": true,
    "password": "password",
    "name": "Nick Cerminara",
    "_id": "59ce4a552d40846c0b938085"
  },
  "$init": true,
  "iat": 1506691722,
  "exp": 1506778122
}
    "admin": true,
    "password": "password",
    "name": "Nick Cerminara",
    "_id": "59ce4a552d40846c0b938085"
  },
  "$init": true,
  "iat": 1506691722,
  "exp": 1506778122
}

This means that everyone who can receive that token has all information about the user. For example, if we would insert an email field for the user it will also show up there. This is even true for expired tokens. So every token the user ever created has all information about him inside, including the cleartext password.

This is obviously a huge security flaw.
A possible fix would be to only include selected attributes inside the payload of the token, not the entire model.

@chris-sev
Copy link
Member

Really appreciate the help on this one!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants