sidorares / node-mysql2

:zap: fast mysqljs/mysql compatible mysql driver for node.js
https://sidorares.github.io/node-mysql2/
MIT License
4k stars 604 forks source link

It fails connection when server uses PAM #438

Open pangiole opened 7 years ago

pangiole commented 7 years ago

When I try to connect as a user the server expects to authenticate via the PAM Authentication Plugin, the following error is thrown

Error: Client does not support authentication protocol requested by server;
       consider upgrading MariaDB client

After reading your node-mysql2 docs, and some investigations, I finally realized there's no support for mysql_clear_password capabilities yet. I realized you provided an authSwitchHandler configuration setting to properly react when the server asks for specific authentication methods.

Couldn't it be useful providing mysql_clear_password the same way mysql_native_password authentication capabilities have been already provided internally? After reading the official MySQL Clear Text Authentication piece of documentation, we could easily implement it in Javascript.

sidorares commented 7 years ago

I'm a bit on the fence about if we should have clear text authentication bundled in core, as I'd like to discourage it's use. Maybe we should add it as example using initial handshake with mysql_clear_password plugin auth (not possible yet but should be there soon) or as authSwitch handler ( possible right now, I reckon handler function would be less than ~20 lines of js )

Implementation of clear text auth in mysqljs/mysql: https://github.com/mysqljs/mysql/blob/a0f2cec26ee86536dbc1c2837b92b191ca9618f1/lib/protocol/Auth.js#L88-L106 and https://github.com/mysqljs/mysql/blob/c226ee74a14d99a1bf9a3d7a9606c34ffff533e4/lib/protocol/sequences/Handshake.js#L77

sidorares commented 7 years ago

Couldn't it be useful providing mysql_clear_password the same way mysql_native_password authentication capabilities have been already provided internally?

yes, this is another option, might go this route

pangiole commented 7 years ago

Despite it seems an unsafe way to send passwords over the network, mysql_clear_password is just one of the MySQL Authentication Methods specified in

https://dev.mysql.com/doc/internals/en/authentication-method.html

and requested in

http://dev.mysql.com/worklog/task/?id=1054

The simplest piece of Javascript I had to write to make mysqlj support it:

dbConf.authSwitchHandler = (data, cb) => {
    if (data.pluginName === 'mysql_clear_password') {
      // https://dev.mysql.com/doc/internals/en/clear-text-authentication.html
      var password = dbConf.password + '\0';
      var buffer = Buffer.from(password);
      cb(null, buffer);
    }
  };
sidorares commented 7 years ago

What about this: add support for cleartext auth and "old auth" but by default only allow to use them when connecting over unix socket or to localhost or over ssl

pangiole commented 7 years ago

It seems you're too much concerned of addressing possible MySQL authentication method's vulnerabilities (particularly those you believe could arise from cleartext_authentication)

Shouldn't those vulnerability concerns be addressed by MySQL designers themselves rather than by this node-mysql2 driver? Official MySQL documentation is just listing all the authentication methods a fully-compliant driver-client should be able to support

https://dev.mysql.com/doc/internals/en/authentication-method.html

As many other MySQL drivers do (for other programming languages such as Java, Python, Ruby etc.) shouldn't this node-mysql2 driver for Javascript just support all of the above authentication methods despite their possible vulnerabilities?

Why shall this node-mysql2 deny some authentication methods (though they must be provided) if some conditions are not met (such as denying cleartext_authentication if no SSL/TLS is involved) ? The official MySQL documentation doesn't state that.

You're probably not considering that in certain private networks (such as those for big private corporations) password are simply transmitted clear_text because there are Kerberos Distribution Centers in place to provide security. That's one of the reasons MySQL designers have been running the following task

http://dev.mysql.com/worklog/task/?id=1054

and I suppose there are many other reasons the most recent MySQL servers delegate authentication to an external PAM - Pluggagle Authentication Module. That's why this node-mysql2 should send password in clear text when asked by the server side.

sidorares commented 7 years ago

That's why this node-mysql2 should send password in clear text when asked by the server side.

I agree with most of what you say, but I think at API level it should be very clear when credentials are sent securely and when not. Yes, there might be a lot of scenarios when this is not important ( local db, connecting over ssh tunnel etc ). mysqljs/mysql currently only support mysql_native_password and mysql_old_password and insecureAuth flag is required for latter to be used. We probably should be consistent with that.

@dougwilson Do you have an opinion on this ?

dougwilson commented 7 years ago

I have been silently following this conversation and don't have any strong opinions on it, but I do agree generally that it should be opt-in only. Even MySQL's own documentation shows they also make it opt-in only for their own clients (http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html).

sidorares commented 7 years ago

@angiolep I'm happy to bundle mysql_clear_password and mysql_old_auth AuthSwitch handlers and have them called automatically when server request this type of auth, but only if the client explicitly turned on insecureAuth switch. It's not super high priority for me right now - feel free to send PR if you want this to be implemented faster

nathanewakefield commented 7 years ago

Not sure if this is where I should ask... but does anyone have steps for implementing a solution to the original error?

elephantjim commented 7 years ago

FWIW, mysql_clear_password is needed to be able to connect to an Aurora database on AWS RDS when using IAM auth tokens. The connection to the RDS instance is over SSL, and the authentication token is sent in the clear (because it's already an HMAC signature).

@angiolep 's fix in https://github.com/sidorares/node-mysql2/issues/438#issuecomment-255343793 worked for me. Thanks!

kennu commented 6 years ago

I also ran into this problem when trying to connect Sequelize to AWS RDS Aurora using IAM authentication tokens. Too bad the mysql2 driver does not work out of the box. Had to spend time looking how to implement a workaround for Sequelize. I was able to pass the previously given fix like this in the Sequelize constructor options:

dialectOptions: {
  authSwitchHandler: authSwitchHandler,
  ssl: 'Amazon RDS',
},