Is this kind of code prone to SQL injection? - sql-injection

I am doing a project for my school and I am task to debug all of the issues found using the application call HPE Fortify. The report generated by the application only indicates the code below prone to SQL injection:
String sql = " select Distinct p1.desc1,p2.desc2 from parameter p1"
+" inner join parameter p2"
+" on p1.ParaCode1='CR_DERIVE' and p1.ParaCode2=p2.Desc2"
+" inner join parameter p3"
+ " on p2.ParaCode3=p3.ParaCode1 and p3.ParaCode3=p2.Desc2"
+" where p2.paracode1='ATTRIBUTE'"
+ " and p2.ParaCode2='" + ddl_attribute.SelectedValue + "'";
But not the codes below:
strSQL = "SELECT Paracode2 FROM Parameter WHERE Paracode1 = 'PROGMGR' AND Desc1 = '" + login + "' AND Status = 'A' ";
I would like to know the reason why as I am unclear regarding SQL injection and I am new to this. Thanks for the response

You're concatenating some application variables into your SQL query string, so the safety depends on how those variables' values were set. Did they come from some untrusted input? Or were they set from some safe application data?
If HPE Fortify has analyzed your code and knows how your login variable was assigned its value, it may be able to tell that it's safe to use in an SQL expression. Whereas it may not be able to make that conclusion about the SelectedValue variable, so it assumes it's unsafe and therefore could cause an SQL vulnerability.
The Perl language does something similar, without the use of a tool like HPE Fortify. Every Perl variable is either "tainted" or "untainted" depending on where it got its value. So you can tell whether a variable is safe to use in SQL, or in eval() or other possible code-injection situations. It's a pity more languages don't support something similar.
But I agree with other commenters that you should learn to use query parameters. It's easy and it's safe. And you can stop getting eyestrain figuring out if you've balanced your quotes-within-quotes correctly.
Your code sample looks like it might be Java. Here's an example in Java:
strSQL = "SELECT Paracode2 FROM Parameter"
+ " WHERE Paracode1 = 'PROGMGR' AND Desc1 = ? AND Status = 'A' ";
Notice the ? placeholder for the parameter has no single-quotes around it within the SQL string. You must not put SQL quotes around the placeholder.
PreparedStatement stmt = con.PreparedStatement(sql);
stmt.setString(1, login);
ResultSet rs = stmt.executeQuery();
For more information to help you understand SQL injection, you might like my presentation SQL Injection Myths and Fallacies, or the video of me delivering that talk: https://www.youtube.com/watch?v=VldxqTejybk

Related

How do you pass variables into Mirth Database Reader Channels for SQL expressions?

I can't find any documentation on how to manager parameters into Database Reader SQL statements?
-> this is a simplified example: I am not looking for scripting a variable to "yesterday" which is easy to express in SQL. That's not the point. I have have more complex variables in the actual SQL statement I'm trying to martial in. I just want to know how to get variables into the SQL form if possible.
-> "you can just do that in JavaScript": the actual queries I need to run are about a hundred lines long, I don't want to maintain and debug a query build by concatenating strings and then deal with escaping 'quoted' things everywhere in the SQL. I really prefer to maintain an actual SQL statement that copy/paste works in a SQL IDE.
How do we pass in parameters into the SQL block at the bottom of the Database Reader form?
SELECT patientsex, visitnumber, samplereceived_dt, sr_d, sr_t, orderpriority, orderrequestcode, orderrequestname
FROM mydata.somedata
WHERE sr_d = (${DateUtil.getCurrentDate('yyyyMMdd')})::integer;
JavaScript is the feasible way to achieve this, with SQL statements defined inside Mirth connect or have the SQL statements bundled in a stored procedure then use SQL server's Exec command within Mirth connect to call the stored procedure while passing the parameters (interestingly using JavaScript).
For example
var dbConn;
try {
dbConn = DatabaseConnectionFactory.createDatabaseConnection('','DB:Port\instance','user','pass');
var paramList = new java.util.ArrayList();
paramList.add($('patientId'));
paramList.add($('lastName'));
paramList.add($('firstName'));
var result = dbConn.executeCachedQuery("SELECT * FROM patients WHERE patientid = ? AND lastname = ? AND firstname = ?) ",paramList);
while (result.next()) {
//you can reference by column index like so...
//result.getString(1);
}
} finally {
if (dbConn) {
dbConn.close();
}
}
Should be noted that the parameters you add to the list MUST be in order.

Avoiding SQL injections with prepare and execute

A line of code like
my $sql_query = "SELECT * FROM Users WHERE user='$user';";
might introduce an SQL injection vulnerability into your program. To avoid this one could use something like
my $sth = $dbh->prepare("SELECT * FROM Users WHERE user='?';");
$dbh->execute($user);
However, in the code I am currently working on the following is used
$sql_query = "SELECT * FROM Users WHERE user='" . $user . "';";
$dbh->prepare($sql_query);
$dbh->execute();
Does this actually work? If yes, are there any differences to what I would have done? What are the advantages and disadvantages?
my $sth = $dbh->prepare("SELECT * FROM Users WHERE user='?'");
This won't work because it's searching for a literal '?' character — not a parameter. If you try to send a value for the parameter, MySQL will be like, "what do you want me to do with this?" because the query has no parameter placeholder.
If you want to use a parameter, you must NOT put the parameter placeholder inside string delimiters in the SQL query, even if the parameter will take string or datetime value:
my $sth = $dbh->prepare("SELECT * FROM Users WHERE user=?");
The next example:
$sql_query = "SELECT * FROM Users WHERE user='" . $user . "'";
$dbh->prepare($sql_query);
$dbh->execute();
That will run the query, but it's NOT safe. You can prepare any query even if it has no parameters.
Using prepare() is not what makes queries safe from SQL injection. What makes it safer is using parameters to combine dynamic values instead of doing string-concatenation like you're doing in this example.
But using parameters does require the use of prepare().
PS: You don't need to put ; at the end of your SQL queries when you run them one at a time programmatically. The separator is only needed if you run multiple queries, like in an SQL script, or in a stored procedure. In your examples, the ; is harmless but MySQL doesn't require it, and it will just ignore it.

Allowed approaches for addressing SQL Injection in Fortify

I have the following code for implementing a drop down menu. The user selects two values, and, based on the input, the query selects the relevant columns to be shown to the user:
String sql = "SELECT :first, :second from <table>";
sql = sql.replace(":first", <first_user_input>);
sql = sql.replace(":second", <second_user_input>);
Now, Fortify catches these lines as allowing SQL Injection. My question is, will Fortify accept a RegEx based whitelisting approach as a solution?
I was thinking of adopting the following approach:
if(isValidSQL(<first_user_input>) && isValidSQL(<second_user_input>))
{
sql = sql.replace(...);
}
else
throw new IllegalSQLInputException
and
public boolean isValidSQL(String param)
{
Pattern p = Pattern.compile([[A-Z]_]+); //RegEx for matching column names like "FIRST_NAME", "LNAME" etc. but NOT "DROP<space>TABLE"
Matcher m = p.matcher(param);
return m.matches(param);
}
So, would Fortify accept this as a valid whitelisting method? If Fortify works on the below grammar:
valid_sql := <immutable_string_literal> //Something like "SELECT * FROM <table> WHERE x = ?" or //SELECT * FROM <table>
valid_sql := valid_sql + valid_sql //"SELECT * FROM <table>" + "WHERE x = ?"
then I don't suppose RegEx-based whitelisting would work. In that case, only this example would work, since it appends strings that are fixed at run time. I would not prefer this approach since it would result in a massive amount of switch-case statements.
Thank You
So, after trying the above mentioned approach, I found that Fortify is still catching the line as a potential threat. However, after reading about how Fortify works, I'm not sure if the "strictness" comes from Fortify itself, or the corporate rules defined in the XML configuration file for the same. I think that, if one's corporate rules allow regular expression-based whitelisting to work, then that should do the trick.

SQLRPGLE DB2 Select into variable

I'm having problems with my query returning errors. What I have at this moment is this:
comi C X'7D'
SqlQuery S 500A
VarSel S 10A
VarSel = *blanks;
SqlQuery = 'select USU into VarSel from FXXUSELN ' +
'where USU = upper(' + comi + %trim(pusuario) +
comi + ') and PWDUSU = upper(' + comi +
%trim(ppassword) + comi + ')';
Exec SQL execute immediate :SqlQuery;
psqlcod = sqlcod;
But when I try to debug that code, it returns -084: UNACCEPTABLE SQL STATEMENT as sqlcod. Printing the SqlQuery variable in the debugger call I get this string, which seems to be correct:
select USU into VarSel from FXXUSELN where USU = upper('usua
rio') and PWDUSU = upper('password')
Anybody knows how to solve this problem so I can make a login stored procedure? Thanks in advance.
The problem is that SELECT INTO can not be dynamically prepared.
If you look at the Invocation section of SELECT INTO in the manual you'll see:
This statement can only be embedded in an application program. It is an executable statement that cannot be dynamically prepared. It must not be specified in REXX.
Also note the following Actions Allowed on SQL Statements section of appendix B in the manual which summarizes where/how each statement may be used.
Finally, if what you tried had worked, you'd have opened yourself up to SQL Injection attacks. Generally speaking, for any DB you should avoid dynamic SQL. If you must use dynamic SQL, then you should use parameter makers instead of directly concatenating user input into the string.
In your case, there's no need for dynamic SQL if the first place. Static SQL is easier, safer, and allows the use of SELECT INTO
exec SQL
select USU into :VarSel from FXXUSELN
where USU = upper(:pusuario)
and PWDUSU = upper(:ppassword);

SSIS - Passing Parameters to an ADO .NET Source query

I know this has been asked earlier.
Most of the answers were not relevant.
Google, shows that the solution is to configure the expression in the "data flow task" and set the query.
However in the ADO .NET source, when I try to preview the output I keep getting "Must declare the variable '#'"
It does not show the full variable in this error - "#[User::GLOBAL_PARAMETER]"
I think that's because "[USER::" isn't the correct syntax inside a SQL; but then how does one set it ?!
From your description it seems like you are having an error due to using the variable name inside the query string as opposed to the processed variable value. In other words:
"SELECT * FROM #[User::TABLE]" in the expression builder would be WRONG
"SELECT * FROM " + #[User::TABLE] would be CORRECT
It would help if you shared the expression you are using as a query