python MySQLdb: use ssl without certificate - python

I have a mysql server running on AWS which requires to authenticate via SSL (but does not require a user certificate).
What I tried:
Connecting without a cert works fine via SequelPro (GUI):
It also works when using mysqlconnector with an empty ssl param: 'ssl_ca': ''. But unfortunately not with MySQLdb.
I tried (using a connection string)
1.
conn = sqlalchemy.create_engine(
con_str,
connect_args={'ssl':{'ca': ''}})
pd.read_sql_query('select id from mytable limit 1', conn)
2.
conn = sqlalchemy.create_engine(
# the following is used to enforce mysqlconnector usage
con_str.replace("mysql:", "mysql+mysqlconnector:"),
connect_args={'ssl_ca':''})
pd.read_sql_query('select id from mytable limit 1', conn)
The second works fine, the first not. Of course I also tried around with the bare connectors (MySQLdb.connect() and mysql.connector.connect()) and experienced the same behaviour and couldn't bring MySQLdb to work.
Question:
Can you give me some hints on how to use SSL in MySQLdb without a cert (and key)?
Further Background:
We switched to AWS from another provider so unfortunately no more ssh like before and now SSL. And I'm not administrating the DB so I can't make it using user certificates, am only being forced to use ssl without any certs.
A colleague explained that this is okay from a security viewpoint, because the server sends a cert. We trust him that he is the one belonging to the corresponding URL because we trust the CA.

Might not work in your case, but I was also looking to do this in pymysql, and it seems like passing a dict with any key works:
connect_args={'ssl': {'key': 'whatever'}}
But then I found out mysql-connector-python tries ssl even without any parameters. I switched because of another reason.

Related

how to listen for incoming jdbc connections?

let's say that me and a partner are working on a python application that needs to connect to a database, exemple mysql:
import mysql.connector
mydb = mysql.connector.connect(host="databaseURL",user="user",passwd="userPassword")
l am trying to hide my credentials from the code, but referencing them in anyway (from a file, environment variable, substitution ...etc.) doesn't work since he can simply print the value, or get them from memory, and clearing memory isn't an option in my use case.
one idea that l thought about is using a proxy, that sits between the python app and the database, this way l could connect to the db with some proxy credentials instead. exemple:
import mysql.connector
mydb = mysql.connector.connect(host="proxyURL",user="proxyUser",passwd="proxyPassword")
basically if the credentials are valid, the proxy gonna request the actual credentials, and use them to connect to the database.
The difficulty that l found is how to to make a server listen for incoming JDBC connections? i.e. how to create a jdbc proxy. Otherwise is the approach even correct?
thinking about it, l don't think that's even possible, since each database has it own JDBC driver that communicates in its unique way with the database. this means that l need to write different proxies for each database.

Problems connecting to MariaDB using the Python mysql.connector

I am trying to use Python 3.7 to connect to various MySQL and MariaDB databases using ver 8.0.18 of the mysql.connector (installed via pip as the mysql-connector-python package).
In this particular instance, I am trying to connect to a MariaDB 5.5.52 instance, but seem to be having the same problem on other systems.
If I attempt to connect thus:
cnx = mysql.connector.connect(user=c['user'], password=c['password'], host=c['host'], database=c['database'])
I get
mysql.connector.errors.ProgrammingError: 1045 (28000): Access denied for user '<user name>'#'<ip address>' (using password: YES)
The mysterious thing is that I can use a client application (JetBrains DataGrip) to connect from the same PC to the databases in question without any problems, so I am confident that the credentials are valid and there aren't any network or similar problems preventing the connection (i.e. port 3306 is open).
The only common factor I can find seems to be the mysql.connector. I've checked the manual and it looks like the syntax is correct.
UPDATE Following #makozaki's advice to use a different connector (pymysql) the code works. So it would definitely appear to be the mysql.connector that's the problem. I might try rolling it back to a previous version to see if that fixes it (unless anyone out there knows of a workaround).
I was able to fix this same error message for mysql.connector by adding in the additional parameter 'tls_versions':
cnx = mysql.connector.connect(user=c['user'], password=c['password'], host=c['host'], database=c['database'], 'tls_versions'=['TLSv1.1', 'TLSv1.2'])
This works because, as of the update 8.0.18, you can now specify the TLS version if it doesn't match the version of your database.
So far as I can tell, this turned out to be something to do with character encoding. The password I was using had some strange characters in it, including a British pound sign and an accented foreign (European) character.
For reasons I don't yet understand, the DataGrip client passed these without any problem, yet the mysql.connector somehow nobbled them.I suspect that this is something to do with encoding, although everything is set (or defaults to) utf-8.
I've changed the password(s) to ones encoded in base64 and the problem appears to have been solved, although I am frustrated that I haven't got to the bottom of why it occurred in the first place.

SQLAlchemy orm styles, how to make special drive to your connection string

I use pypy, pypyodbc and SQLAlchemy.
I have problem of odbc connections.
I use:
engine = create_engine('mssql+pyodbc://dbuser:dbpasswd#localhost/dbname', echo = False)
Session = sessionmaker(bind=engine)
style try to connect the database.
The error is:
C:\pypy\site-packages\sqlalchemy\connectors\pypyodbc.py:82: SAWarning: No driver
name specified; this is expected by PyODBC when using DSN-less connections
"No driver name specified; "
The reason of this error, I find the connect parameter
DRIVER={SQL Server Native Client}
is not transmit to the engine, in other word, I want to know how to set DRIVER string for this connections style for SQLALchemy.
I've run into the same issue with Sybase ASE and after looking at the pyodbc.py source code you can pass GET-like parameters in your url. As an example (working for me):
sybase+pyodbc://username:password#hostname:5000/dbname?driver=Adaptive Server Enterprise
It's also sort of documented here with the connection string syntax being dialect://user:password#host/dbname[?key=value..]
Hope that helps
You may have also be been suffering from updating your SqlAlchemy version. As of the latest release (v1.0) you need to explicitly define your driver in the connection string for Microsoft SQL Server.
See:
Changed in version 1.0.0: Hostname-based PyODBC connections now require the SQL Server driver name specified explicitly. SQLAlchemy cannot choose an optimal default here as it varies based on platform and installed drivers.
http://docs.sqlalchemy.org/en/latest/dialects/mssql.html#hostname-connections
See:
Connecting to database using SQLAlchemy
I had this error message and fixed it by adding this to the end of the connection string:
"?driver=SQL+Server+Native+Client+10.0"

Is there a way to set secure_auth to false in MySQLdb.connect in Python 2.7.5?

I am attempting to run a script written in Python 2.7.5 (not using Django). When it tries to connect to a remote mysql server with the MySQLdb.connect() method it throws the following error:
_mysql_exceptions.OperationalError: (2049, "Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)")
I have done reading about this issue:
Django/MySQL-python - Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)
mysql error 2049 connection using old (pre-4-1-1) authentication from mac
Is there a way to set a parameter in the MySQLdb.connect() method to set secure_auth to false? Without having to change any passwords or running the command from the cmd line. I have looked at the official docs and there does not appear to be anything in there.
I have tried adding secure_auth=False to the parameters but throws an error (shown in the code below).
Python:
def get_cursor():
global _cursor
if _cursor is None:
try:
db = MySQLdb.connect(user=_usr, passwd=_pw, host='external.website.com', port=3306, db=_usr, charset="utf8")
# tried this but it doesnt work (as expect but tried anyway) which throws this error
# TypeError: 'secure_auth' is an invalid keyword argument for this function
# db = MySQLdb.connect(user=_usr, passwd=_pw, host='external.website.com', port=3306, db=_usr, charset="utf8", secure_auth=false)
_cursor = db.cursor()
except MySQLdb.OperationalError:
print "error connecting"
raise
return _cursor
I spent an inordinate amount of time working through the MySQLdb source code and determined that this simply cannot be done without patching the MySQLdb's C wrapping code. Theoretically, you should be able to pass the SECURE_CONNECTION flag to specify that do not want to use the insecure old passwords:
MySQLdb.connect(..., client_flags=MySQLdb.constant.CLIENT.SECURE_CONNECTION)
But the MySQLdb code never actually checks that flag, and never configures the secure_connection option when calling the MySQL connection code, so it always defaults to requiring new-style passwords.
Possible fixes include:
Patch the MySQLdb code
Use an old version of the MySQL client libraries
Update the passwords on the MySQL server
Create a single new user with a new-style password
Sorry I don't have a better answer. I just ran into this problem myself!
I know Moses answer as been validated but I wanted to offer my work around based on what he suggested.
I had previously installed mysql_python for my python and had the brew version of mysql installed.
I deteleted all of that.
I look for a way to install MySQLdb by looking for it last stable version with the source.
I compiled them (followed the isntructions here), installed them and then I looked for a stable version of MySQL client (MySQL website is the best place for that) and install the 5.5 version which was perfectly fitting my requirements.
I made mysql to launch itself automatically and then restarted my computer (but you can just restart apache) and check that all path were correct and the right includes are in the right places (you can check that against the link above).
And now it all works fine!
Hope it helps.
SSL is a separate paramter that you can set in the connection paramter...Here is a note from the source code...Try checking mysql_ssl_set() documentation.
ssl
dictionary or mapping, contains SSL connection parameters;
see the MySQL documentation for more details
(mysql_ssl_set()). If this is set, and the client does not
support SSL, NotSupportedError will be raised.
This document talks about all the secure parameters - http://dev.mysql.com/doc/refman/5.0/en/mysql-ssl-set.html...
I don't see anything to disable secure auth in glance..

Connect to SQL Server instance using pymssql

I'm attempting to connect to a SQL Server instance from a Windows box using pymssql (version 2.0.0b1-dev-20111019 with Python 2.7.1). I've tried the most basic approach from the console:
import pymssql
c = pymssql.connect(host = r'servername\instance',
user = 'username',
password = 'userpassword')
In response to this, I get the very helpful error: InterfaceError: Connection to the database failed for an unknown reason.
I am reasonably confident that the connection information is correct, as it works when I use adodbapi, with the following commands:
import adodbapi
c = adodbapi.connect(r'Provider=sqloledb;Data Source=servername\instance;User ID=username;password=userpassword;'
c.close
I've tried adding the port number to the host parameter, with the same result. Does anyone have a suggestion on how to go about resolving this issue?
Incidentally, I've read the responses at "Unable to connect to SQL Server via pymssql". The OP eventually resolved his issue by correctly configuring FreeTDS, which, from what I can tell, is not used by pymssql on Windows.
Based on #cha0site's recommendation, I have tried using just the hostname, rather than the hostname and instance. This resulted in the same error, but it seemed to take longer to generate the error (though the traceback still indicates the same line). The reason I have been specifying the instance is that I was not able to connect using SSMS unless I specified the instance, so I assumed that it would be necessary for other connections.
I've now also tried pymssql.connect(host='servername', user='username', password='userpassword', database='instance') with the same result (based on #Sid's comment). Based on the pymssql documentation, I believe the database parameter is used to specify the initial database that the user is to be connected to, rather than the instance.
Just to clarify, "instance" is the name provided during installation of SQL Server, not a database within that installation. It occurs to me that it's possible that pymssql does not support this notation, so I will look into re-configuring the SQL Server instance so that it is not required.
I've now re-installed SQL Server as a default instance, rather than a named instance, which allows me to connect without specifying the instance name. adodbapi still works (without /instance), but pymssql still returns the same error. I've also removed and re-installed pymssql from a freshly downloaded archive (still the same version).
Check your freetds.conf file and see if you have set the port 1219., then check again the connexion:
DB = pymssql.connect(host='DB',user='youruser',password='yourpwd',database='yourDBname')
Edit: example of my freetds.conf file Python:
host = 'IP'
port = 1219
To specify host=servername\instance or server=servername\instance, the SQL Server Browser service must be on the SQL Server machine.

Categories