prevent SQL injection in django forms - mysql

I use this for validation:
class MyValidationForm(forms.Form):
title = forms.CharField()
body = forms.Textarea()
taxonomy = forms.IntegerField()
and this is my class-based view:
class blog_createpost(dashboardBaseViews):
template_name = "dashboardtems/blog_createpost.html"
model = {}
def post(self, request, *args, **kwargs):
form = MyValidationForm(request.POST)
if not form.is_valid():
return HttpResponse("not valid")
new_data = post(title=request.POST['title'],
body=request.POST['body'],
description=request.POST['description'],
taxonomy=get_object_or_404(taxonomy,
pk=request.POST['taxonomy']),
writer=request.user)
new_data.save()
return HttpResponse("done")
like you see i check my received request validation in this line: if not form.is_valid(): and its working on but when i add some SQL-command inside my form inputs. it does not preventing to insert the value inside database!..
means i have a field in database which contains some value like select * from user where 1=1!.
doesn't it cause sql-injection danger from user inputs?...

You have misunderstood what SQL injection means. Django has successfully protected you from such an attack, the string "select * from user where 1=1" is being treated as data, not as a command, and ended up as a value in the database.
A SQL injection attack alters the SQL that is being executed by the database. A successful attack tricks the database into executing data as commands instead. You'd not end up with select * from user where 1=1 as a value, but instead you end up with the attacker getting access to all results from the user table.
A classic error is to not properly escape data, by constructing the SQL command as a string. Lets say the server uses the following query to look up data for the current user:
SELECT * FROM user WHERE username='$user_id'
where $user_id comes from the request. Normally that'd be a login name, say
user_id = "zopatista"
so the query becomes
SELECT * FROM user WHERE username='zopatista'
If the server does not protect against SQL injection attacks, an attacker can replace user_id and inject more SQL commands:
user_id = "zopatista' OR 1=1 -- "
so after simply interpolating that string into the query, now the server will send the following SQL to the database:
SELECT * FROM user WHERE username='zopatista' OR 1=1 -- '
and suddenly the meaning of the query command has changed and the database will return all rows rather than just one row matching the login name.
The classic XKCD joke on SQL injection goes a step further and injects SQL code that deletes the whole table, rather than try to get access to more information.
A server protecting against SQL injection will make sure that user-provided data is always parameterised, sending the data to the database driver separately from the query to make sure it can never be seen as part of the query.
As long as you use Django's models and querysets, you'll be protected from SQL injection attacks. You would only be at risk if you mixed extra() or RawSQL() with user data without using their parameter features.

Related

Method has no supported translation to SQL(Linq to Sql)

After I execute a query on the database, and try to print the result of that execution, I got this error:
Method has no supported translation to SQL.
My code:
Table<User> users = DAL.DALConnection.Database.GetTable<User>();
var query = from user in users
where user.Get_UserName().ToString() == username
select user;
foreach (User user in query)
Console.WriteLine(user);
Is Get_UserName() a C# function you've written in your code? If so, the error coming back makes sense, because SQL Server doesn't know about that function.
Instead, you would probably want to do something like where user.username == username, assuming your table has a username field.

How to pass a where clause simply but safely via a console command in ZF2?

I'm creating a quick and dirty console controller to create fixtures from a database table.
I'd like to use a where clause to limit this - but would like to make the controller a little less dirty and prevent injections.
My current console command specification is:
db create fixture <table_name> [--where=]
The controller action has:
$tableName = $request->getParam('table_name');
$where = $request->getParam('where');
$queryString = "select * from `$tableName`";
if (!is_null($where)) {
$queryString .= " where $where";
}
$resultSet = $dbAdapter->query(
$queryString,
DbAdapter::QUERY_MODE_EXECUTE
);
Now, I know this is obviously wide open to SQL injection - as confirmed when I ran the following:
db create fixture hit_log --where="\`timestamp\` between '2015-01-20 00:00:00' and '2015-01-30 00:00:00'; delete from hit_log limit 1";
So, what would be a good strategy to fix this?
I'm thinking of JSON notation --where='{"timestamp":["between","2015-01-20","2015-02-30"]}' - but then I'll have to write a translator to handle different tests like "=", "LIKE", and "BETWEEN".
Edit:
I've put checks in the controller action to ensure it is a console only request, and will error out if a user somehow manages to route via the http router.
This then assumes that a developer is running the command, and would have access to the database anyway. I guess this is more trying to protect against error than malice.

How to update a row in a MySQL database using Ruby's Sequel toolkit?

This should be the simplest thing but for some reason it's eluding me completely.
I have a Sequel connection to a database named DB. It's using the Mysql2 engine if that's important.
I'm trying to update a single record in a table in the database. The short loop I'm using looks like this:
dataset = DB["SELECT post_id, message FROM xf_post WHERE message LIKE '%#{match}%'"]
dataset.each do |row|
new_message = process_message(row[:message])
# HERE IS WHERE I WANT TO UPDATE THE ROW IN THE DATABASE!
end
I've tried:
dataset.where('post_id = ?', row[:post_id]).update(message: new_message)
Which is what the Sequel cheat sheet recommends.
And:
DB["UPDATE xf_post SET message = ? WHERE post_id = ?", new_message, row[:post_id]]
Which should be raw SQL executed by the Sequel connector. Neither throws an error or outputs any error message (I'm using a logger with the Sequel connection). But both calls fail to update the records in the database. The data is unchanged when I query the database after running the code.
How can I make the update call function properly here?
Your problem is you are using a raw SQL dataset, so the where call isn't going to change the SQL, and update is just going to execute the raw SQL. Here's what you want to do:
dataset = DB[:xf_post].select(:post_id, :message).
where(Sequel.like(:message, "%#{match}%"))
That will make the where/update combination work.
Note that your original code has a trivial SQL injection vulnerability if match depends on user input, which this new code avoids. You may want to consider using Dataset#escape_like if you want to escape metacharacters inside match, otherwise if match depends on user input, it's possible for users to use very complex matching syntax that the database may execute slowly or not handle properly.
Note that the reason that
DB["UPDATE xf_post SET message = ? WHERE post_id = ?", new_message, row[:post_id]]
doesn't work is because it only creates a dataset, it doesn't execute it. You can actually call update on that dataset to run the query and return number of affected rows.

Hibernate createSQLQuery - How does it validate the SQL?

I have some code that translates a user's search word into a MySQL query:
String sql = String.format("SELECT * FROM my_table WHERE my_column = '%s'", value);
HibernateUtil.getCurrentSession().createSQLQuery(sql);
To test if I was protected—and because I think it would be fun to learn in this way—I wanted to try to SQL inject my own application. So I searched for:
x'; DROP TABLE test;--
which results in the following query:
SELECT * FROM my_table WHERE my_column = 'x'; DROP TABLE test;--
But Hibernate throws a SQLGrammarException. When I run this code via phpMyAdmin, it correctly drops the test table.
How is Hibernate validating my SQL? Perhaps more importantly—is this protecting me against SQL injection or should I be using setParameter. If it's not protecting me, can I have an example of some SQL that will perform the injection. I think it would be fun to actually verify.
You are protected against execution of more than one statement because createSQLQuery allows exactly one statement. It is not Hibernate which protects you here, but your JDBC driver respectively your database - because it does not know how to handle the separator ; in the context of a single statement.
But you are still not safe against SQL injection. There are plenty of other possibilities to inject SQL in that case. Just one example:
Imagine you are searching for some user specific items in your query:
String sql = String.format(
"SELECT * FROM my_table WHERE userId = %s AND my_column = '%s'",
currentUserId, value);
The user can now enter:
x' OR '1' = '1
Which will lead to the SQL:
SELECT * FROM my_table WHERE userId = 1234 AND my_column = 'x' OR '1' = '1'
And because AND has higher precedence, he will see all items - even those of other users.
Even your provided example can be dangerous, for example
x' OR (SELECT userName FROM USER) = 'gwg
will let me know if your database contains a user that is called gwg (assuming that I know your database layout, which I could find out with similar queries).
According to Hibermate documentation, the method createSQLQuery "Create a new instance of Query for the given SQL string", so we can assume that Hibernate do the SQL checking for a single query on every call of this method.
Important: createSQLQuery is deprecated on Hibernate, please check out the link given above to see newers ways to execute SQL queries.
Now, speaking about how you could protect yourself from SQL injection, the best way to do it is using parameters on your query.
This question has the exactly example you are in need for, please check it out.
Hope this help you in your studies, good luck!

Test whether or not log-in system is protected against sql injection

So for a school project I have to make a site with a log-in system. It has a username and password field, and a submit button. It compares the username and password with those in a MySQL database. If the combination is in the database, the user may proceed, else they are redirected to the log-in page. I use prepared PDO statements for my database connection.
Now my teacher wants me to test the safety by performing sql attacks on the log-in system. Unfortunately I have no idea what to put in these boxes, and what would be the outcome. For example, I have tried putting values in both username and password fields that will return true, like this:
1==1, 1===1, 0 is null
But I do not know whether or not I have succeeded and if attackers may access or truncate my database by these sort of statements.
Html code:
<form method="post" action="includes/login.php">
<input type="text" name="gebruikersnaam" >
<input type="password" name="wachtwoord" >
<input type="submit" value="login">
</form>
Php authentication:
$myusername=$_POST['gebruikersnaam'];
$mypassword=$_POST['wachtwoord'];
$sql="SELECT * FROM leerling WHERE leerlingnummer='$myusername' and wachtwoord='$mypassword'";
$sql2="SELECT * FROM lop WHERE gebruikersnaam='$myusername' and wachtwoord='$mypassword'";
$statement2=$conn->prepare($sql2);
$statement2->execute();
$count2=$statement2->rowcount();
if($count2==1){proceed}
$statement = $conn->prepare($sql);
$statement->execute();
$count= $statement->rowcount();
if($count==1){proceed}
else {deny access}
Imagine this query:
SELECT id FROM users WHERE email=? AND password=? LIMIT 1
Now imagine the values would be foo#bar.hello and an empty string for password:
SELECT id FROM users WHERE email='foo#bar.hello' AND password='' LIMIT 1
This would not be harmful if these credentials are not in your database. Now lets give different input:
For email we fill in an empty string, and for password we insert ' OR 1=1 (Note the first apostrophe)
Your teacher wants you to find out whether this means your SQL server will execute the following query:
SELECT id FROM users WHERE email='' AND password='' OR 1=1 LIMIT 1
SQL is a declarative language with which you declare the expectations you have for your result. If your server would interpret our input as stated above, the first users id would be considered correct, simply because one is equal to one.
As it is, it is susceptible to SQL injection
The thing to look at when trying to inject is can I close the statement I'm in right now and add more to the end.
so if you enter username = 123456' -- the SQL statement becomes SELECT * FROM leerling WHERE leerlingnummer='123456' --' and wachtwoord='unimortant'
the -- starts a comment so all it does is select whatever student number is entered ignoring the password.
PDO has good alternatives to prevent this from happening called Prepared Statements. You declare your SQL queries and only enter where user infromation is going to be entered by using a ? or :lable and then bind user input to those points. The page does a way better job at explaining it. This way all user data is clearly seperated from the rest of the command and will be treated as a litteral string rather than a command. Stopping SQL injection.
$sql="SELECT * FROM users WHERE username = '{$_REQUEST['username']}' AND password = '{$_REQUEST['password']}";
Write query in such format will avoid sql injection.
$sql = 'SELECT * FROM users WHERE username = ? AND password = ?';
$query = $db->prepare($sql);
$query->bindParam(1, $_REQUEST['username']);
$query->bindParam(2, $_REQUEST['password']);
Or pass the parameter to mysql_real_escape_string function and then pass to queries.
$username=mysql_real_escape_string($_REQUEST['username']);
$password=mysql_real_escape_string($_REQUEST['password']);