First timer here, so I'll try to be as thorough as possible.
I'm a rather new programmer and started working at a new company where I've been attempting to prevent some SQL injection in a specific piece of PHP code that was leftover from an old project, but is needed in my rewrite of it.
This project is in Laravel as a backend and AngularJS as the frontend.
I've attempted several ways to prevent the SQL injection but have gotten the same error in all of them.
Error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'll.created_at BETWEEN '?' AND '?' UNION SELECT 1 as type, ll.id, ll.name, ll.ema' at line 1
Here is the original code in question:
if (!empty($request['inst'])) {
$institution = $request['inst'];
$inst = ' ll.inst_id = ' . $request['inst'] . ' AND ';
$instCount = ' customers.inst_id = :inst AND ';
$instEvent = ' location_id = :inst AND ';
} else {
$inst = ' ';
$instCount = ' ';
$instEvent = ' ';
$institution = "";
}
$startTime = $request['start'];
$endTime = $request['end'];
$sql = " SELECT 0 as type ,ll.id as lead_name, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM customers ll LEFT JOIN leads_statistics ls ON ll.id = ls.lead_id"
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ll.created_at BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 1 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.meeting_set_first BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 2 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.is_active = 1 AND ls.occurred_date BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 3 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.is_active = 1 AND ls.not_show_date BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 4 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.is_active = 1 AND ls.cancel_meeting_date BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 5 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.is_active = 1 AND ls.sale_date BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 6 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.is_active = 1 AND ls.cancel_sale_date BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 7 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.extended_date BETWEEN '" . $request['start'] . "' AND '" . $request['end']
. "' UNION SELECT 8 as type, ll.id, ll.name, ll.email, ll.updated_at, u.employee_name, ls.meeting_set_date, ls.meeting_set_first FROM leads_statistics ls LEFT JOIN customers ll ON ls.lead_id = ll.id "
. " LEFT JOIN users u ON ll.userUpdate = u.employee_id WHERE $inst ls.is_active = 1 AND ls.meeting_set_date BETWEEN '" . $request['start'] . "' AND '" . $request['end'] . "'";
$leads = DB::select($sql);
Here are some of the techniques I've used after perusing the internet and SO at length.
- Placeholders (? instead of all the variables and creating an array at the end with all the variables 9 times over)
- Named Bindings example:
DB::select($sql, ["inst" => $institution, "start" => $startTime, "end" => $endTime,])
- Named bindings Named bindings with
PDO::ATTR_EMULATE_PREPARES => true,
so I can use :inst, :start, :end multiple times - SQL variable bindings with @ symbols
Results of techniques:
- No protection - works fine, I receive the proper results
- Placeholders - I get the above error, but the SQL has the proper data in the placeholders. I can take the resulting SQL and run it through the phpmyadmin server SQL query and I receive the data as expected.
- Named Bindings - Doesn't work at all. I get an error stating
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
- Named Bindings with
PDO::ATTR_EMULATE_PREPARES => true,
- works, however it affects all the data I then pull from my server turning things such as numbers to strings or worse. This plays havoc with typing all over the place - SQL variable binding - didn't work either, received the above error
I am unsure if it's possible to turn this giant SQL query into Laravel Eloquent or Query Builder, though I have tried.
Anyone have any ideas? Any help would be immensely appreciated, I've been wrestling with this for a few weeks now.