i know this might sound simple but i want a second opinion.
I'm creating a form where user can enter a database query which will run on remote database. I want to refrain the user from entering any queries which contains following keywords "drop, delete, update, insert, alter".
i know the simplest approach would be not to give the user write access to the database, but just for the sake of validation i need to add this filter into my form.
here's what i have done so far
Query = "Select * from table_name"
validation = re.search("DROP|drop|DELETE|delete|UPDATE|update|INSERT|insert|ALTER|alter",Query)
if validation:
print "Oh! you are not supposed to enter that!!"
else:
print "We're cool"
Have i covered every possible scenarios? or the user can still give me a hard time?
Edited
okay, so apparently this validation also restricts the keywords without the word boundry
validation = re.search("drop|delete|update|insert|alter",Query,flags=re.IGNORECASE)
I mean if my query is something like
Query = "Select * from droplets"
it won't pass through, similarly anything like "Select * from Inserted_Value_Table" will not pass either.
validation = re.search("\bdrop\b|\bdelete\b|\bupdate\b|\binsert\b|\balter\b",Query,flags=re.IGNORECASE)
now again i wonder if something like this would do the job?
You can alternatively use any(). But your approach seems to be sufficient:
t = Query.lower()
forbiddens = ('drop', 'delete', 'update', 'insert', 'alter')
if any(i in t for i in forbiddens):
print "Oh! you are not supposed to enter that!!"
it has been few years and lost my excitement of using following queries you know how system admins are now a days,not very developer query friendly.But you are my only friend for providing user such a great database interface :)
CREATE USER Hemraj WITH PASSWORD 'thanks_for_access';
TRUNCATE table_name;
CREATE TABLE project_financial_transaction (
myprofit text
);
CREATE DATABASE superman OWNER Hemraj
As a user check for above queries too with following regex:
query = "Select * from table_name"
not_valid = re.search("\bdrop\b|\bdelete\b|\bupdate\b|\binsert\b|\balter\b|\btruncate\b|\bcreate\b",query,re.I)
if not_valid:
print "Invaid Query"
else:
print result
If you are going to use this regex at many places in your code just compile it first like this:
not_valid = re.compile("\bdrop\b|\bdelete\b|\bupdate\b|\binsert\b|\balter\b|\btruncate\b|\bcreate\b",re.I)
if not_valid.search(query):
print "Invalid Query"
this way you can keep your code clean and more readable :)
Related
I am coding a database manager in Python using SQLite3 and tkinter, and I am attempting to build a query function. Each element in my database has several attributes: 'name', 'path', 'seen', 'quality', 'franchise', 'genre' and 'tags'.
If possible, I want the user to be able to select certain options in the GUI and then create a request to the database, but the problem is that the user should be able to select any or all of those attributes to be filtered out or into the query. For example, one query might be asking for all the objects in the database with the name "Tony", franchise "toy Story", and genre "Action", whereas another query might just want all objects of seen "yes".
I've been having a lot of trouble with this, and though I've been tempted to, I can't hardcode every permutation of parts of the SQL Select statement, and I feel like there's a better way anyways I can't see. I've tried setting a 'default statement':
SELECT * FROM objects WHERE and then adding onto it like genre IS ? and if franchise matters than AND franchise IS ?, but then I run into the problem of I don't know how to format the substitutions dynamically. I'm pretty sure this can be done, so I'd love any help. Thanks!
You're absolutely on the right path. Consider building up a list of WHERE clauses and a parallel list of substitutions. In this example, I'm using strings, but you get the idea:
subs = []
where = []
where.append( "name = ?" )
subs.append( "Tony" )
where.append( "franchise = ?" )
subs.append( "Toy Story" )
sql = "SELECT * FROM movies WHERE " + (" AND ".join(where)) + ";"
query = cursor.execute( sql, subs )
Can anyone "translate" this MySQL query to Django chain or Q(). This is just an example (but valid) query, but I want to see it with my own eyes, because Django documentation doesn't look very noob friendly in this aspect and I couldn't get those chains and stuff to work.
mysql -> SELECT position, COUNT(position) FROM
-> (SELECT * FROM log WHERE (aspect LIKE 'es%' OR brand LIKE '%pj%')
-> AND tag IN ('in','out')) AS list
-> GROUP BY position ORDER BY COUNT(position) DESC;
While I think chaining filters would be more convenient for me in the future, this below just seems way more straightforward at the moment.
query = "the query from above"
cursor.execute(query)
[new_list.append([item for item in row ]) for row in cursor]
...or should I just quit()
from django.db.models import Count,Q
myfilter = [Q(aspect__startswith="es")|Q(brand__contains="pj"),tag__in=['in','out']]
# condition 1 OR condition2 AND condition3
qry = Log.objects.filter(*myfilter).values('position').annotate({"count":Count('position')})
print(qry.values())
I think maybe gets you the same answer using django ... close anyway I think
whether it is better or not i suppose is in the eye of the beholder
myfilter = Q(aspect__startswith="es") | Q(brand__contains="pj"), Q(tag__in=['in', 'out'])
qry = Log.objects.filter(*myfilter).values('position').annotate(Count('position')).order_by('-position__count')
had to add Q before tag__inbrackets on myfilter did not make a difference
annotate({"count":Count('position')}) gave an error QuerySet.annotate() received non-expression(s)
and to sort in descending order had to add
.order_by('-position__count')
output is a dictionary, but that's perfect for displaying on the website
So You were close. Now the data is matching mysql output and I understand it better how to do the QuerySets and filters. Thanks
I'm working on a registration site and right now I am trying to make multiple bases at the same time.
I have 2 databases, one called Tables, and the other called Digit.
I want to use the SAME function for both of them, only to manage 2 databases at the same time, differ by the front end choice.
I tried to use %s as a place holder for the table name, while i have a dict at the beginning for the different databases (1: Tables, 2 : Digit)
cursor.execute("SELECT * FROM %s WHERE active = %s AND isFull = %s ORDER BY minLevel" , [bases[DB], 1,0])
This is the code I wrote, I was hoping to switch the databases based on the DB given from the front end of the site.
And.. it didn't work. I'm really stuck here, and I am not sure if this way is even legal...
Thanks a head for you help!
I figured it out!
thanks to another post by the way - thank to cursor.query( 'select * from %s;', ('thistable',) ) throws syntax error 1064: ...near ' 'thistable' ' at
the problem is you cant use %s on "database variables", like column, databases, etc.
the way to work around it is to build the query as a string beforehand and then to use execute in this format :
cursor.execute (q , [variable])
while q is the pre-built query.
and while building the query to add the database wanted
so the code above should look like (i have a pre built dictionary)
q= "SELECT * FROM " + dict[Number] + " WHERE active = %s AND isFull = %s ORDER BY minLevel"
cursor.execute(q , [1,0])
while dict is the name of the dictionary, number is the variable i got from the front end. and active , is Full and minLevel are columns of mine i use.
hope it will help somebody!
I'm creating a change-password page for a website, which requests the new password and the current password. The old password is hashed and salted using the scrypt library then compared to the password stored in the sqlite3 database, and if these are a match, the new password is hashed and the database is updated. However I am having difficulty executing the update command, as it throws a sqlite3.OperationalError: unrecognised token: "\" error. The execute statement currently has the following code:
c.execute("UPDATE users SET password = \'{0}\' WHERE memberID = \'{1}\'".format(newPas, memID))
Initially we believed this error to have been caused by the use of ' in the string formatting due to the presence of ' within the new password itself, so this was run again as:
c.execute("UPDATE users SET password = \"{0}\" WHERE memberID = \"{1}\"".format(newPas, memID))
This successfully runs, but doesn't actually change anything in the database. We also attempted to create a query string and then execute the string.
query = "UPDATE users SET password = {0} WHERE memberID = {1}".format(newPas, memID)
c.execute(query)
This caused a sqlite3.OperationalError: near "'\xa1\x91\x9f\x88\xfb\x81\x12\xd4\xc2\xf9\xce\x91y\xf0/\xe1*#\x8aj\xc7\x1d\xd3\x91\x14\xcb\xa4\xabaP[\x02\x1d\x1b\xabr\xc7\xe4\xee\x19\x80c\x8e|\xc0S\xaaX\xc6\x04\xab\x08\x9b\x8e\xd7zB\xc6\x84[\xfb\xbc\x8d\xfc'": syntax error. I believe that this is caused by the presence of ' and " characters within the password, but I am unsure how to get around this issue as these are added by the hashing process and thus removing them would change the password.
The password I would like to add is:
b'\xa1\x91\x9f\x88\xfb\x81\x12\xd4\xc2\xf9\xce\x91y\xf0/\xe1*#\x8aj\xc7\x1d\xd3\x91\x14\xcb\xa4\xabaP[\x02\x1d\x1b\xabr\xc7\xe4\xee\x19\x80c\x8e|\xc0S\xaaX\xc6\x04\xab\x08\x9b\x8e\xd7zB\xc6\x84[\xfb\xbc\x8d\xfc'
I was wondering if anyone could share some insights into why it isn't liking the "\" character or why it isn't updating the database, and point me in the right direction to making it work. If you need more information or code snippets or just want to yell at me, please don't hesitate to! Thank you in advance :)
A couple of things with your code:
You should not use format to build your queries like this. This leaves you liable to SQL injection and, whilst you might sanitise your inputs in this case, it's a bad habit that will bite you.
All changes need to be committed to the database to actually take effect. This is why your second query did not throw an error but equally did not make any changes to the database.
The correct formatting of this query would be:
conn = sqlite3.connect('my_db.db')
c = conn.cursor()
query = "UPDATE users SET password = ? WHERE memberID = ?"
c.execute(query, (newPas, memID))
conn.commit() # To finalise the alteration
As a side note, the cursor expects a tuple in this case, so a common stumbling block comes when passing single values:
query = "UPDATE users SET password = ? WHERE memberID = 'abc'"
c.execute(query, (newPas)) # Throws "incorrect number of bindings" error
# Use this instead i.e. pass single value as a tuple
c.execute(query, (newPas,))
You could use format to create variable field names in a query, since placeholders are not allowed in this case:
fields = ['a', 'b', 'c']
query = "UPDATE users SET {} = ?".format(random.choice(fields))
in addition to using it to help you build big queries where it would be tedious to manually type all the placeholders, and difficult to ensure that you had the correct number if your code changed:
my_list = ['a', 'b',...., n]
placeholders = ', '.join(['?' for item in my_list])
query = "INSERT .... VALUES = ({})".format(placeholders)
You should use parametrized queries something like this:
c.execute("""UPDATE users SET password = ? WHERE memberID = ?;""", (newPas, memID))
It will allow to avoid nasty things like SQL-injections.
I'm writing an app engine app, that has some input fields.
Are there any concerns I need to take into account about something like this?
You should validate that any input from your users meets your requirements. For example, if you need an positive integer, then make sure that's what you got.
As far as strings, you don't have to worry about SQL (or GQL in this case) injection as long as you don't construct the queries by hand. Instead use the GqlQuery.bind() method, or the methods provided by Query to pass the values (e.g., Query.filter()). Then these classes will take care of formulating the query so you don't need to worry about the syntax (or injection).
Examples (adapted from the docs linked to previously):
# this basic string query is safe
query = Song.all()
query.filter('title =', self.request.get('title'))
# a GqlQuery version of the previous example
query = GqlQuery("SELECT x FROM Song WHERE title = :1",self.request.get('title'))
# sanitize/validate when you have requirements: e.g., year must be a number
query = Song.all()
try:
year = int(self.request.get('year')) # make sure we got a number
except:
show error msg
query.filter('year =', year)
There are a number of forms libraries that do most of the hard work for you - you should use one of them. Django's newforms library is included with App Engine.