SQL Server adds b'...' to the jwt tokens I store - python

I am storing JWT tokens used in authentication for a web service in a SQL Server database. I've declared the column that holds the tokens as type nvarchar(max) and am passing them into the database as simple strings. When I insert the token, SQL Server adds b'...' to it. For example, say I add the token ABC123, then it stores b'ABC123'.
This is causing problems down the line as when I compare the token stored in the database to the token being passed through the api, the comparison fails due to the additional characters (the database seems to have literally added a lower case b and two single quotes to the stored string).
I know I can just strip the b and quotes off my string once I pull it from the database, but I'd like to know why SQL Server is doing this and how I can prevent it from doing it.
Anyway, any insight would be much appreciated.
EDIT: is it possible pyodbc is doing this? Here is my code to insert:
cnxn = pyodbc.connect("<connection string>")
crsr = cnxn.cursor()
crsr.execute("insert into jwt values (?,?)", [userId, str(auth_token)])
Perhaps it is confused between Python 3 and Python 2 strings? (I'm using Python 3.6.) In that case, how would I fix it?

Turns out it was python's "str" conversion. jwt.encode returns a byte array which str then turns into b'...'. The solution was to decode the bytes explicitly instead of using str. So my new insert method is:
crsr.execute("insert into jwt values (?,?)", [userId, auth_token.decode("utf-8")])
Really a simple solution but one that is very obscure. Hopefully my efforts with this help someone else!

Related

Python MySQL connector returns bytearray instead of regular string value

I am loading data from one table into pandas and then inserting that data into new table. However, instead of normal string value I am seeing bytearray.
bytearray(b'TM16B0I8') it should be TM16B0I8
What am I doing wrong here?
My code:
engine_str = 'mysql+mysqlconnector://user:pass#localhost/db'
engine = sqlalchemy.create_engine(engine_str, echo=False, encoding='utf-8')
connection = engine.connect()
th_df = pd.read_sql('select ticket_id, history_date', con=connection)
for row in th_df.to_dict(orient="records"):
var_ticket_id = row['ticket_id']
var_history_date = row['history_date']
query = 'INSERT INTO new_table(ticket_id, history_date)....'
For some reason the Python MySql connector only returns bytearrys, (more info in (How return str from mysql using mysql.connector?) but you can decode them into unicode strings with
var_ticket_id = row['ticket_id'].decode()
var_history_date = row['history_date'].decode()
Make sure you are using the right collation, and encoding. I happen to use UTF8MB4_BIN for one of my website db tables. Changed it to utf8mb4_general_ci, and it did the trick.
Producing a bytearray is now the expected behaviour.
It changed with mysql-connector-python 8.0.24 (2021-04-20). According to the v8.0.24 release notes, "Binary columns were returned as strings instead of 'bytes' or 'bytearray'" behaviour was a bug that was fixed in that release.
So producing a Python binaryarray is the correct behaviour, if the database column is a binary type (e.g. binary or varbinary). Previously, it produced a Python string, but now it produces a binaryarray.
So either change the data type in the database to a non-binary data type, or convert the binaryarray to a string in your code. If the column is nullable, you'll have to check for that first; since attempting to invoke decode() method on None would produce an error. You'll also have to be sure the bytes represent a valid string, in the character encoding being used for the decoding/conversion.
Much easier...
How to return str from MySQL using mysql.connector?
Adding mysql-connector-python==8.0.17 to requirements.txt resolved this issue for me
"pip install mysql-connector-python" from terminal

Insert into sqlite3 a null date from pyramid framework using sqlalchemy

python 2.7
pyramid 1.3a4
sqlalchemy 7.3
sqlite3.7.9
from sqlite prompt > I can do:
insert into risk(travel_dt) values ('')
also
insert into risk(travel_dt) values(Null)
Both result in a new row with a null value for risk.travel_dt but when I try those travel_dt values from pyramid, Sqlalchemy gives me an error.
In the first case, I get sqlalchemy.exc.StatementError:
SQLite Date type only accepts python date objects as input
In the second case, I get Null is not defined. When I use "Null", I get the first case error
I apologize for another question on nulls: I have read a lot of material but must have missed something simple. Thanks for any help
Clemens Herschel
While you didn't provide any insight into the table definition you're using or any example code, I am guessing the issue is due to confusing NULL (the database reserved word) and None (the Python reserved word).
The error message is telling you that you need to call your SQLA methods with valid python date objects, rather than strings such as "Null" or ''.
Assuming you have a Table called risk containing a Column called travel_dt, you should be able to create a row in that table with something sort of like:
risk.insert().values(travel_dt=None)
Note that this is just a snippet, you would need to execute such a call within an engine context like that defined in the SA Docs SQL Expression Language Tutorial.

Python - Informix - Character to numeric conversion error (-1213)

While trying to update an Informix table via a Python script I am getting the error:
Character to numeric conversion error (-1213)
The db request:
cursor.execute("update sales set pid = ? where sid = '1'", price)
Table sales:
sid | oid | price | pid
The column I want to update has the data type money(10,2)
I tried inserting as a Decimal value a String and a Float...which one would be appropriate?
I am using Informix 10.00 TC6 on Win 2003 Server -
CLIENT_LOCALE=en_us.819 - DB_LOCALE=en_us.819
To connect to Informix I am using pyodbc.
Nothing about money in the supported data types so not sure if it works at all (http://code.google.com/p/pyodbc/wiki/DataTypes)
Your DB driver is converting your code to SQL. You can use the Informix debugger to see what SQL it produces. I know Informix doesn't like thousand separators in its SQL.
There are two possible string-to-numeric conversions in the SQL you show.
Converting '1' to the same type as sid.
Converting the value passed as the placeholder (variable price which is substituted for ?).
What is the value in price? What does Python print its value as?
Informix is pretty flexible about doing conversions for you, so the first conversion should be fine. Normally, you'd only supply single quotes if sid is a string column, but it should convert fine.
So, the other issue is: what is PyODBC doing with price?
You might be able to see what happens if you set the environment variable SQLIDEBUG=2:xyz and run the program. It will generate a file with a prefix xyz_ which can be processed with sqliprint, assuming it is available to you. That will tell you what is sent between the client (Python) and the data server. Depending on what you find, it may point the finger at the client side code or the server side code.

How do you escape strings for SQLite table/column names in Python?

The standard approach for using variable values in SQLite queries is the "question mark style", like this:
import sqlite3
with sqlite3.connect(":memory:") as connection:
connection.execute("CREATE TABLE foo(bar)")
connection.execute("INSERT INTO foo(bar) VALUES (?)", ("cow",))
print(list(connection.execute("SELECT * from foo")))
# prints [(u'cow',)]
However, this only works for substituting values into queries. It fails when used for table or column names:
import sqlite3
with sqlite3.connect(":memory:") as connection:
connection.execute("CREATE TABLE foo(?)", ("bar",))
# raises sqlite3.OperationalError: near "?": syntax error
Neither the sqlite3 module nor PEP 249 mention a function for escaping names or values. Presumably this is to discourage users from assembling their queries with strings, but it leaves me at a loss.
What function or technique is most appropriate for using variable names for columns or tables in SQLite? I'd would strongly prefer to do able to do this without any other dependencies, since I'll be using it in my own wrapper.
I looked for but couldn't find a clear and complete description of the relevant part of SQLite's syntax, to use to write my own function. I want to be sure this will work for any identifier permitted by SQLite, so a trial-and-error solution is too uncertain for me.
SQLite uses " to quote identifiers but I'm not sure that just escaping them is sufficient. PHP's sqlite_escape_string function's documentation suggests that certain binary data may need to be escaped as well, but that may be a quirk of the PHP library.
To convert any string into a SQLite identifier:
Ensure the string can be encoded as UTF-8.
Ensure the string does not include any NUL characters.
Replace all " with "".
Wrap the entire thing in double quotes.
Implementation
import codecs
def quote_identifier(s, errors="strict"):
encodable = s.encode("utf-8", errors).decode("utf-8")
nul_index = encodable.find("\x00")
if nul_index >= 0:
error = UnicodeEncodeError("NUL-terminated utf-8", encodable,
nul_index, nul_index + 1, "NUL not allowed")
error_handler = codecs.lookup_error(errors)
replacement, _ = error_handler(error)
encodable = encodable.replace("\x00", replacement)
return "\"" + encodable.replace("\"", "\"\"") + "\""
Given a string single argument, it will escape and quote it correctly or raise an exception. The second argument can be used to specify any error handler registered in the codecs module. The built-in ones are:
'strict': raise an exception in case of an encoding error
'replace': replace malformed data with a suitable replacement marker, such as '?' or '\ufffd'
'ignore': ignore malformed data and continue without further notice
'xmlcharrefreplace': replace with the appropriate XML character reference (for encoding only)
'backslashreplace': replace with backslashed escape sequences (for encoding only)
This doesn't check for reserved identifiers, so if you try to create a new SQLITE_MASTER table it won't stop you.
Example Usage
import sqlite3
def test_identifier(identifier):
"Tests an identifier to ensure it's handled properly."
with sqlite3.connect(":memory:") as c:
c.execute("CREATE TABLE " + quote_identifier(identifier) + " (foo)")
assert identifier == c.execute("SELECT name FROM SQLITE_MASTER").fetchone()[0]
test_identifier("'Héllo?'\\\n\r\t\"Hello!\" -☃") # works
test_identifier("北方话") # works
test_identifier(chr(0x20000)) # works
print(quote_identifier("Fo\x00o!", "replace")) # prints "Fo?o!"
print(quote_identifier("Fo\x00o!", "ignore")) # prints "Foo!"
print(quote_identifier("Fo\x00o!")) # raises UnicodeEncodeError
print(quote_identifier(chr(0xD800))) # raises UnicodeEncodeError
Observations and References
SQLite identifiers are TEXT, not binary.
SQLITE_MASTER schema in the FAQ
Python 2 SQLite API yelled at me when I gave it bytes it couldn't decode as text.
Python 3 SQLite API requires queries be strs, not bytes.
SQLite identifiers are quoted using double-quotes.
SQL as Understood by SQLite
Double-quotes in SQLite identifiers are escaped as two double quotes.
SQLite identifiers preserve case, but they are case-insensitive towards ASCII letters. It is possible to enable unicode-aware case-insensitivity.
SQLite FAQ Question #18
SQLite does not support the NUL character in strings or identifiers.
SQLite Ticket 57c971fc74
sqlite3 can handle any other unicode string as long as it can be properly encoded to UTF-8. Invalid strings could cause crashes between Python 3.0 and Python 3.1.2 or thereabouts. Python 2 accepted these invalid strings, but this is considered a bug.
Python Issue #12569
Modules/_sqlite/cursor.c
I tested it a bunch.
The psycopg2 documentation explicitly recommends using normal python % or {} formatting to substitute in table and column names (or other bits of dynamic syntax), and then using the parameter mechanism to substitute values into the query.
I disagree with everyone who is saying "don't ever use dynamic table/column names, you're doing something wrong if you need to". I write programs to automate stuff with databases every day, and I do it all the time. We have lots of databases with lots of tables, but they are all built on repeated patterns, so generic code to handle them is extremely useful. Hand-writing the queries every time would be far more error prone and dangerous.
It comes down to what "safe" means. The conventional wisdom is that using normal python string manipulation to put values into your queries is not "safe". This is because there are all sorts of things that can go wrong if you do that, and such data very often comes from the user and is not in your control. You need a 100% reliable way of escaping these values properly so that a user cannot inject SQL in a data value and have the database execute it. So the library writers do this job; you never should.
If, however, you're writing generic helper code to operate on things in databases, then these considerations don't apply as much. You are implicitly giving anyone who can call such code access to everything in the database; that's the point of the helper code. So now the safety concern is making sure that user-generated data can never be used in such code. This is a general security issue in coding, and is just the same problem as blindly execing a user-input string. It's a distinct issue from inserting values into your queries, because there you want to be able to safely handle user-input data.
So my recommendation is: do whatever you want to dynamically assemble your queries. Use normal python string templating to sub in table and column names, glue on where clauses and joins, all the good (and horrible to debug) stuff. But make sure you're aware that whatever values such code touches has to come from you, not your users[1]. Then you use SQLite's parameter substitution functionality to safely insert user-input values into your queries as values.
[1] If (as is the case for a lot of the code I write) your users are the people who have full access to databases anyway and the code is to simplify their work, then this consideration doesn't really apply; you probably are assembling queries on user-specified tables. But you should still use SQLite's parameter substitution to save yourself from the inevitable genuine value that eventually contains quotes or percent signs.
If you're quite certain that you need to specify column names dynamically, you should use a library that can do so safely (and complains about things that are wrong). SQLAlchemy is very good at that.
>>> import sqlalchemy
>>> from sqlalchemy import *
>>> metadata = MetaData()
>>> dynamic_column = "cow"
>>> foo_table = Table('foo', metadata,
... Column(dynamic_column, Integer))
>>>
foo_table now represents the table with the dynamic schema, but you can only use it in the context of an actual database connection (so that sqlalchemy knows the dialect, and what to do with the generated sql).
>>> metadata.bind = create_engine('sqlite:///:memory:', echo=True)
You can then issue the CREATE TABLE .... with echo=True, sqlalchemy will log the generated sql, but in general, sqlalchemy goes out of its way to keep the generated sql out of your hands (lest you consider using it for evil purposes).
>>> foo_table.create()
2011-06-28 21:54:54,040 INFO sqlalchemy.engine.base.Engine.0x...2f4c
CREATE TABLE foo (
cow INTEGER
)
2011-06-28 21:54:54,040 INFO sqlalchemy.engine.base.Engine.0x...2f4c ()
2011-06-28 21:54:54,041 INFO sqlalchemy.engine.base.Engine.0x...2f4c COMMIT
>>>
and yes, sqlalchemy will take care of any column names that need special handling, like when the column name is a sql reserved word
>>> dynamic_column = "order"
>>> metadata = MetaData()
>>> foo_table = Table('foo', metadata,
... Column(dynamic_column, Integer))
>>> metadata.bind = create_engine('sqlite:///:memory:', echo=True)
>>> foo_table.create()
2011-06-28 22:00:56,267 INFO sqlalchemy.engine.base.Engine.0x...aa8c
CREATE TABLE foo (
"order" INTEGER
)
2011-06-28 22:00:56,267 INFO sqlalchemy.engine.base.Engine.0x...aa8c ()
2011-06-28 22:00:56,268 INFO sqlalchemy.engine.base.Engine.0x...aa8c COMMIT
>>>
and can save you from possible badness:
>>> dynamic_column = "); drop table users; -- the evil bobby tables!"
>>> metadata = MetaData()
>>> foo_table = Table('foo', metadata,
... Column(dynamic_column, Integer))
>>> metadata.bind = create_engine('sqlite:///:memory:', echo=True)
>>> foo_table.create()
2011-06-28 22:04:22,051 INFO sqlalchemy.engine.base.Engine.0x...05ec
CREATE TABLE foo (
"); drop table users; -- the evil bobby tables!" INTEGER
)
2011-06-28 22:04:22,051 INFO sqlalchemy.engine.base.Engine.0x...05ec ()
2011-06-28 22:04:22,051 INFO sqlalchemy.engine.base.Engine.0x...05ec COMMIT
>>>
(apparently, some strange things are perfectly legal identifiers in sqlite)
The first thing to understand is that table/column names cannot be escaped in the same sense than you can escape strings stored as database values.
The reason is that you either have to:
accept/reject the potential table/column name, i.e. it is not guaranteed that a string is an acceptable column/table name, contrarily to a string to be stored in some database; or,
sanitize the string which will have the same effect as creating a digest: the function used is surjective, not bijective (once again, the inverse is true for a string that is to be stored in some database); so not only can't you be certain of going from the sanitized name back to the original name, but you are at risk of unintentionally trying to create two columns or tables with the same name.
Having understood that, the second thing to understand is that how you will end up "escaping" table/column names depends on your specific context, and so there is more than one way to do this, but whatever the way, you'll need to dig up to figure out exactly what is or is not an acceptable column/table name in sqlite.
To get you started, here is one condition:
Table names that begin with "sqlite_" are reserved for internal use. It is an error to attempt to create a table with a name that starts with "sqlite_".
Even better, using certain column names can have unintended side effects:
Every row of every SQLite table has a 64-bit signed integer key that
uniquely identifies the row within its table. This integer is usually
called the "rowid". The rowid value can be accessed using one of the
special case-independent names "rowid", "oid", or "rowid" in place
of a column name. If a table contains a user defined column named
"rowid", "oid" or "rowid", then that name always refers the
explicitly declared column and cannot be used to retrieve the integer
rowid value.
Both quoted texts are from http://www.sqlite.org/lang_createtable.html
From the sqlite faq, question 24 (the formulation of the question of course does not give a clue that the answer may be useful to your question):
SQL uses double-quotes around identifiers (column or table names) that contains special characters or which are keywords. So double-quotes are a way of escaping identifier names.
If the name itself contains double quotes, escape that double quote with another one.
Placeholders are only for values. Column and table names are structural, and are akin to variable names; you can't use placeholders to fill them in.
You have three options:
Appropriately escape/quote the column name everywhere you use it. This is fragile and dangerous.
Use an ORM like SQLAlchemy, which will take care of escaping/quoting for you.
Ideally, just don't have dynamic column names. Tables and columns are for structure; anything dynamic is data and should be in the table rather than part of it.
I made some research because I was unsatisfied with the current unsafe answers, and I would recommend using the internal printf function of sqlite to do that. It is made to escape any identifier (table name, column table...) and make it safe for concatenation.
In python, it should be something like that (I'm not a python user, so there may be mistakes, but the logic itself works):
table = "bar"
escaped_table = connection.execute("SELECT printf('%w', ?)", (table,)).fetchone()[0]
connection.execute("CREATE TABLE \""+escaped_table+"\" (bar TEXT)")
According to the documentation of %w:
This substitution works like %q except that it doubles all double-quote characters (") instead of single-quotes, making the result suitable for using with a double-quoted identifier name in an SQL statement.
The %w substitution is an SQLite enhancements, not found in most other printf() implementations.
Which means you can alternatively do the same with single quotes using %q:
table = "bar"
escaped_table = connection.execute("SELECT printf('%q', ?)", (table,)).fetchone()[0]
connection.execute("CREATE TABLE '"+escaped_table+"' (bar TEXT)")
If you find that you need a variable entity name (either relvar or field) then you probably are doing something wrong. an alternative pattern would be to use a property map, something like:
CREATE TABLE foo_properties(
id INTEGER NOT NULL,
name VARCHAR NOT NULL,
value VARCHAR,
PRIMARY KEY(id, name)
);
Then, you just specify the name dynamically when doing an insert instead of a column.

MySQLdb input where strings contain string delimiters

I'm working on a project in Python with MySQLdb. As part of this, I'm moving user details, including salted passwords from one system that generates them to a new one that simply uses them.
Single, double or triple quotes can delineate your string start and end. However, single and double quotes are part of several hashes in the 4.5k or so users I'm migrating. Both tokens appear in about 450 of those salts.
An edited version of the code is as follows
Django.execute ('INSERT INTO auth_user (password) VALUES ("' + user.password + '")')
I have tried swapping between the quote type used in this database cursor object, as and when either quote type or the other are detected, but this still leaves the 150 or so that contain both.
What work arounds can I use for this?
I have tried triple quotes, but they throw a programming error on the cursor object.
Thanks in advance
Query parameters should provide all the proper escaping, for example:
cursor.execute('INSERT INTO auth_user (password) VALUES (%s)', [password])
From the Django docs at: http://docs.djangoproject.com/en/dev/topics/db/sql/
If you're not familiar with
the Python DB-API, note that the SQL
statement in cursor.execute() uses
placeholders, "%s", rather than adding
parameters directly within the SQL. If
you use this technique, the underlying
database library will automatically
add quotes and escaping to your
parameter(s) as necessary. (Also note
that Django expects the "%s"
placeholder, not the "?" placeholder,
which is used by the SQLite Python
bindings. This is for the sake of
consistency and sanity.)

Categories