I found the following in the "e-mail" field of my newsletter subscriber database: ' OR 1=1/*
I know it's a SQL injection, but that's it. I've googled it a little bit, but I'm still on clear on what exactly it's trying to achieve. This occurred early Nov, and to my knowledge we had no outages around that time. Can any of you kind souls tell me what this guy was probably trying and do? Is there any way to know whether he achieved what he was trying to do?
I know virtually nothing about this and I'm worried. :(
'OR 1=1 is an attempt to make a query succeed no matter what
The /* is an attempt to start a multiline comment so the rest of the query is ignored.
An example would be
SELECT userid
FROM users
WHERE username = ''OR 1=1/*'
AND password = ''
AND domain = ''
As you can see if you were to populate the username field without escaping the ' no matter what credentials the user passes in the query would return all userids in the system likely granting access to the attacker (possibly admin access if admin is your first user). You will also notice the remainder of the query would be commented out because of the /* including the real '.
The fact that you can see the value in your database means that it was escaped and that particular attack did not succeed. However, you should investigate if any other attempts were made.
It probably aimed to select all the informations in your table. If you use this kind of query (for example in PHP) :
mysql_query("SELECT * FROM newsletter WHERE email = '$email'");
The email ' OR 1=1/* will give this kind of query :
mysql_query("SELECT * FROM newsletter WHERE email = '' OR 1=1/*");
So it selects all the rows (because 1=1 is always true and the rest of the query is 'commented'). But it was not successful
if strings used in your queries are escaped
if you don't display all the queries results on a page...
The specific value in your database isn't what you should be focusing on. This is likely the result of an attacker fuzzing your system to see if it is vulnerable to a set of standard attacks, instead of a targeted attack exploiting a known vulnerability.
You should instead focus on ensuring that your application is secure against these types of attacks; OWASP is a good resource for this.
If you're using parameterized queries to access the database, then you're secure against Sql injection, unless you're using dynamic Sql in the backend as well.
If you're not doing this, you're vulnerable and you should resolve this immediately.
Also, you should consider performing some sort of validation of e-mail addresses.
Its better if you use validation code to the users input for making it restricted to use symbols and part of code in your input form. If you embeed php in html code your php code have to become on the top to make sure that it is not ignored as comment if a hacker edit the page and add /* in your html code
Related
I have a project that requires we allow users to create custom columns, enter custom values, and use these custom values to execute user defined functions.
Similar Functionality In Google Data Studio
We have exhausted all implementation strategies we can think of (executing formulas on the front end, in isolated execution environments, etc.).
Short of writing our own interpreter, the only implementation we could find that meets the performance, functionality, and scalability requirements is to execute these functions directly within MySQL. So basically taking the expressions that have been entered by the user, and dynamically rolling up a query that computes results server side in MySQL.
This obviously opens a can of worms security wise.
Quick aside: I expect to get the "you shouldn't do it that way" response. Trust me, I hate that this is the best solution we can find. The resources online describing similar problems is remarkably scarce, so if there are any suggestions for where to find information on analogous problems/solutions/implementations, I would greatly appreciate it.
With that said, assuming that we don't have alternatives, my question is: How do we go about doing this safely?
We have a few current safeguards set up:
Executing the user defined expressions against a tightly controlled subquery that limits the "inner context" that the dynamic portion of the query can pull from.
Blacklisting certain phrases the should never be used (SELECT, INSERT, UNION, etc.). This introduces issues, because a user should be able to enter something like: CASE WHEN {{var}} = "union pacific railroad" THEN... but that is a tradeoff we are willing to make.
Limiting the access of the MySQL connection making the query to only have access to the tables/functionality needed for the feature.
This gets us pretty far. But I'm still not comfortable with it. One additional option that I couldn't find any info online about was using the query execution plan as a means of detecting if the query is going outside of its bounds.
So prior to actually executing the query/getting the results, you would wrap it within an EXPLAIN statement to see what the dynamic query was doing. From the results of the EXPLAIN query, you should able to detect any operations (subqueries, key references, UNIONs, etc.) that fall outside of the bounds of what the query is allowed to do.
Is this a useful validation method? It seems to me that this would be a powerful tool for protecting against a suite of SQL injections, but I couldn't seem to find any information online.
Thanks in advance!
(from Comment)
Some Examples showing the actual autogenerated queries being used. There are both visual and list examples showing the query execution plan for both malicious and valid custom functions.
GRANT only SELECT on the table(s) that they are allowed to manipulate. This allows arbitrarily complex SELECT queries to be run. (The one flaw: Such queries may run for a long time and/or take a lot of resources. MariaDB has more facilities for preventing run-away selects.)
Provide limited "write" access via Stored Routines with expanded privileges, but do not pass arbitrary values into them. See SQL SECURITY: DEFINER has the privileges of the person creating the routine. (As opposed to INVOKER is limited to SELECT on the tables mentioned above.)
Another technique that may or may not be useful is creating VIEWs with select privileges. This, for example, can let the user see most information about employees while hiding the salaries.
Related to that is the ability to GRANT different permissions on different columns, even in the same table.
(I have implemented a similar web app, and released it to everyone in the company. And I could 'sleep at night'.)
I don't see subqueries and Unions as issues. I don't see the utility of EXPLAIN other than to provide more info in case the user is a programmer trying out queries.
EXPLAIN can help in discovering long-running queries, but it is imperfect. Ditto for LIMIT.
More
I think "UDF" is either "normalization" or "EAV"; it is hard to tell which. Please provide SHOW CREATE TABLE.
This is inefficient because it builds a temp table before removing the 'NULL' items:
FROM ( SELECT ...
FROM ...
LEFT JOIN ...
) AS context
WHERE ... IS NULL
This is better because it can do the filtering sooner:
FROM ( SELECT ...
FROM ...
LEFT JOIN ...
WHERE ... IS NULL
) AS context
I wanted to share a solution I found for anyone who comes across this in the future.
To prevent someone from entering some malicious SQL injection in a "custom expression" we decided to preprocess and analyze the SQL prior to sending it to the MySQL database.
Our server is running NodeJS, so we used a parsing library to construct an abstract syntax tree from their custom SQL. From here we can traverse the tree and identify any operations that shouldn't be taking place.
The mock code (it won't run in this example) would look something like:
const valid_types = [ "case", "when", "else", "column_ref", "binary_expr", "single_quote_string", "number"];
const valid_tables = [ "context" ];
// Create a mock sql expressions and parse the AST
var exp = YOUR_CUSTOM_EXPRESSION;
var ast = parser.astify(exp);
// Check for attempted multi-statement injections
if(Array.isArray(ast) && ast.length > 1){
this.error = throw Error("Multiple statements detected");
}
// Recursively check the AST for unallowed operations
this.recursive_ast_check([], "columns", ast.columns);
function recursive_ast_check(path, p_key, ast_node){
// If parent key is the "type" of operation, check it against allowed values
if(p_key === "type") {
if(validator.valid_types.indexOf(ast_node) == -1){
throw Error("Invalid type '" + ast_node + "' found at following path: " + JSON.stringify(path));
}
return;
}
// If parent type is table, then the value should always be "context"
if(p_key === "table") {
if(validator.valid_tables.indexOf(ast_node) == -1){
throw Error("Invalid table reference '" + ast_node + "' found at following path: " + JSON.stringify(path));
}
return;
}
// Ignore null or empty nodes
if(!ast_node || ast_node==null) { return; }
// Recursively search array values down the chain
if(Array.isArray(ast_node)){
for(var i = 0; i<ast_node.length; i++) {
this.recursive_ast_check([...path, p_key], i, ast_node[i]);
}
return;
}
// Recursively search object keys down the chain
if(typeof ast_node === 'object'){
for(let key of Object.keys(ast_node)){
this.recursive_ast_check([...path, p_key], key, ast_node[key]);
}
}
}
This is just a mockup adapted from our implementation, but hopefully it will provide some guidance. Should also note, it is best to also implement all of the strategies discussed above as well. Many safeguards are better than just one.
So as the title says I'm curious, can user change the ID of an element through browser? I have a list of inputs - checkboxes, when you click on one of them ajax takes ID of that element and uses it to get data from database, so basically what I'm thinking is that if it is somehow possible to change the ID of the element my database wouldn't be secured. If that's possible, how I should protect it?
Okay, So I get the idea that it wouldn't be secured, If I'd use this way:
<?php
$mysqli = new mysqli("host", "user", "password", "database");
$usuario = $mysqli->real_escape_string($_POST["usuario"]);
$clave = $mysqli->real_escape_string($_POST["clave"]);
$sql=' SELECT * FROM usuarios
WHERE username="'.$usuario.'"
AND pass="'.$clave.'"
';
$mysqli->query($sql);
$mysqli->close();
?>
would it be enough, or there aren't actually safe enough way to protect data?
You are correct that this would be a security hole. The ID attributes could indeed be changed via the browser console.
Yes, they can change it or just make while request faked and you won't tell the difference. Rule of thumb here is NEVER trust any data that comes from user. It means - always validate, sanitize data on server-side, and always assume data that comes in request are there to fool/trick/hack you.
Yes. The user can do anything they like to the DOM once it is in their browser.
They can also execute any JS they like there.
You're worrying about the problem in the wrong place though. Your control ends at the edge of the webserver. Clients can make any HTTP request they like to it and include any id value they want. You need to address security there and not in the browser.
If you want to secure your database then you need to either allow no HTTP request to lead to the secret data being released / changed or you need to write server side rules that limit which HTTP requests can change them.
Typically this would involve Knowing Who The Request Comes From (Authentication) and Knowing Who Can Access Which IDs (Authorization).
A simple approach would be to keep a database that has a users table (including hashed passwords), a "things" table, and an ownership table (which has a column of user ids and a column of thing ids). If the request doesn't include a username and password you can cross reference from the thing id across the ownership table - return an error message instead of what was asked for.
The 1,500 page Access 97 Bible (don't laugh!) that I've been given by my boss to solve his problem doesn't solve my problem of how to solve his problem, because it has nee VBA code.
Let me first make clear that I've made attempts to solve this without (much) coding, and that I've coded quite a bit in VBA already, so I'm basically familiar with most things including recordsets, queries, etc etc but have problems with MS Access limits on how to form a report with data coming from VBA variables. I'm also versatile in most programming languages, but this is not a language problem but rather a "how to/what's possible" problem.
My problem right now is that dragging the query fields into the Detail subform and putting them into cells in columns setting Left and Top with VBA code are moving them alright, but each cell is on a new page. Unfortunately, there is multiple data in each cell that won't conform to the Create Report Guide options available.
So my question is simply this: Can someone point me to working examples of code that create, place, and fill with VBA variable strings, text fields at any coordinate I please on a paper size of my choice?
Edit: The above is not an option, as I understand this will prohibit the client from getting an .mde database. What remains, then, is to merely ask for some sound advice on how to get several rows GROUPed BY weekday and machine (see below) into a recordset or similar for each cell. I guess the best way is to count the number of columns in the table (machines in the sql result) and create 5 rows of these with dummy data, then go through the result rows and place the data in the relevant controls. But if you have ideas for doing this work better and faster, write them as answers.
Sorry for this, I knew there was something I wasn't understanding. Basically, I thought Access supported creating reports dynamically via VBA, ie. "generating pages with data" rather than "preparing a flow of controls connected to datasources". But Access requires that you create an ample amount of dummy, unlinked controls manually, then either fill or hide them and that's how they become "dynamic".
This is for Access 2003 on a remote server accessing local and remote ODBC SQL database tables, if relevant. The goal is to make a week schedule of n columns (n=number of machines at a certain plant) x 5 rows (weekday Mon-Fri), and put 1 or more recordset rows (=scheduled activities for that day on that machine) in each of the "n by 5 table" cells.
If you detect venting frustration in this post I can only ask your forgiveness and hope for your understanding.
So, has many techniques for this:
Ex: 1) using dinamic sql for this:
'Create a function to make sql query
Function MakeMySQlReport(Parameters):
Dim strSql as string
Dim strMyVar as string
strsql = vbnullstring
strsql = "Select " & myVar1 & " as MyFieldVar1, * from myTable where Fieldx =" & Parameters
MyReport.recordSource = ssql
End Function
Ex: 2) create function that returns yours strings:
Function MyString1() as string
MyString1 = 'ABC'
end Function
An in your report, select the textbox will receive the value and type =MyString1()]
I hope this help to you, need more examples?
Solution:
Create many objects manually (grr!)
name them systematically
put them in a Control Array (get all Me.Controls, sift out the ones you're interested in, and put them in an indexed array)
go through the array and change their properties
I have been trying to insert a huge text-editor string in to my database. The application I'm developing allows my client to create and edit their website terms and conditions from the admin part of their website. So as you can imagine, they are incredibly long. I have got to 18,000+ characters in length and I have now received an error when trying to add another load of text.
The error I am receiving is this:
ADODB.Command error '800a0d5d'
Application uses a value of the wrong type for the current operation
Which points to this part of my application, specifically the Set newParameter line:
Const adVarChar = 200
Const adParamInput = 1
Set newParameter = cmdConn.CreateParameter("#policyBody", adVarChar, adParamInput, Len(policyBody), policyBody)
cmdConn.Parameters.Append newParameter
Now this policy I am creating, that is currently 18,000+ characters in length, is only half complete, if that. It could jump to 50 - 60,000! I tried using adLongVarChar = 201 ADO type but this still didn't fix it.
Am I doing the right thing for such a large entry? If I am doing the right thing, how can I fix this issue? ...or if I'm doing the wrong thing, what is the right one?
Try to avoid putting documents in your database if you can. Sometimes it's a reasonable compromise, serialised objects, mark up snippets and such.
If you don't want to query the document with sql the only benefit is the all in one place thing. ie back up your db, you back up your documents as well, and you can use your db connectivity exclusively.
That said nothing is free, carting all that stuff about in your database costs you.
If you can.
have a documents table, User name for the file, and internal name in your documents directory, so the file name is unique in the file system, and a path description, if there could be more than one.
Then just upload and download the selected document as a file, on a get or set of the related database entity.
You'll need to dal with deployment issues, document directory exists, and the account you are running mysql daemon as can see it, but most of the time, the issues you have keeping documents seperate fromthe db, are much easier to deal with than the head scratchers you are running into now.
How can I suggest a list of alternate usernames in case user has selected an invalid or existing username?
The suggestions must be somewhat related. Do I need to use a dictionary of possible usernames?
It depends entirely on what you consider "related". It's hard to define such a meaning for usernames, as they often aren't normal English words. You might wish to create a unique username by appending a random stream of numbers, or by changing some of the letters to numbers ('e' to '3' etc). If you will update your question with what you mean by 'relevant' I will try and tackle that specific issue.
Bad idea. Giving away related usernames allows a skillful attacker to deduce which usernames are in use.
IE if I try and register 'RandomUser' and the system suggests using on of:
RandomUser1
RandomUser2
RandomUser3
RandomUser5
Then I can reasonably surmise that RandomUser4 is a valid username.
Look a this:
http://www.onesoft.dk/post/2007/07/ASPNET-AJAX-username-availability-with-suggestions.aspx
Its build using Ajax & JSON. I'm sure you will be able to adapt it to your technology.
Just add more info to the user name that the user seleced. If you colected also info like birthday, you can add to it the year:
user -> user1985
Or if you're getting a first name:
user -> jose_user
Don't use "automatic" information, because it would make it easy for attackers to deduce valid user names.