mirror of
https://github.com/wavelog/wavelog.git
synced 2026-03-22 10:24:14 +00:00
Merge pull request #2737 from int2001/minor_ref_collector
Collector PR for minor code-cleanups
This commit is contained in:
@@ -1029,6 +1029,7 @@ class Logbook extends CI_Controller {
|
||||
|
||||
if (!is_numeric($clean_station_id) && $clean_station_id !== 'All') {
|
||||
show_404();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->load->model('user_model');
|
||||
@@ -1055,8 +1056,8 @@ class Logbook extends CI_Controller {
|
||||
join lotw_users on ' . $this->config->item('table_name') . '.col_call = lotw_users.callsign
|
||||
where ' . $this->config->item('table_name') .'.station_id in ('. $location_list . ')';
|
||||
|
||||
if ($station_id != 'All') {
|
||||
$sql .= ' and station_profile.station_id = ' . $station_id;
|
||||
if ($clean_station_id != 'All') {
|
||||
$sql .= ' and station_profile.station_id = ' . $clean_station_id;
|
||||
}
|
||||
|
||||
$sql .= " and COL_LOTW_QSL_RCVD <> 'Y' and " . $this->config->item('table_name') . ".COL_TIME_ON < lotw_users.lastupload";
|
||||
|
||||
@@ -107,7 +107,25 @@ class Search extends CI_Controller {
|
||||
$this->db->where('id', xss_clean($this->input->post('id')));
|
||||
$sql = $this->db->get('queries')->result();
|
||||
|
||||
$data['qsos'] = $this->db->query($sql[0]->query);
|
||||
$query = $sql[0]->query;
|
||||
|
||||
// Security: Validate query only accesses allowed tables
|
||||
if (!$this->_validate_query_tables($query)) {
|
||||
show_error("Invalid query: unauthorized table access detected", 403);
|
||||
return;
|
||||
}
|
||||
|
||||
// Security: Block dangerous SQL keywords to prevent SQL injection
|
||||
// Note: 'join' is NOT blocked because legitimate queries use JOINs
|
||||
$blocked = ['insert', 'drop', 'alter', 'create', 'exec', 'script', 'into outfile', 'load_file'];
|
||||
foreach ($blocked as $word) {
|
||||
if (stristr($query, $word)) {
|
||||
show_error("Invalid query: contains blocked keyword", 403);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$data['qsos'] = $this->db->query($query);
|
||||
$this->load->view('adif/data/exportall', $data);
|
||||
}
|
||||
|
||||
@@ -116,7 +134,24 @@ class Search extends CI_Controller {
|
||||
$sql = $this->db->get('queries')->result();
|
||||
$sql = $sql[0]->query;
|
||||
|
||||
// Security: Only allow SELECT queries
|
||||
if (stristr($sql, 'select') && !stristr($sql, 'delete') && !stristr($sql, 'update')) {
|
||||
// Security: Validate query only accesses allowed tables
|
||||
if (!$this->_validate_query_tables($sql)) {
|
||||
show_error("Invalid query: unauthorized table access detected", 403);
|
||||
return;
|
||||
}
|
||||
|
||||
// Security: Block dangerous SQL keywords to prevent SQL injection
|
||||
// Note: 'join' is NOT blocked because legitimate queries use JOINs
|
||||
$blocked = ['insert', 'drop', 'alter', 'create', 'exec', 'script', 'into outfile', 'load_file'];
|
||||
foreach ($blocked as $word) {
|
||||
if (stristr($sql, $word)) {
|
||||
show_error("Invalid query: contains blocked keyword", 403);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(strpos(strtolower($sql),'limit'))) {
|
||||
$sql.=' limit 5000';
|
||||
}
|
||||
@@ -312,4 +347,83 @@ class Search extends CI_Controller {
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that query only accesses allowed tables
|
||||
* Prevents SQL injection via UNION-based attacks on other tables
|
||||
*
|
||||
* @param string $sql The SQL query to validate
|
||||
* @return bool TRUE if query only uses allowed tables, FALSE otherwise
|
||||
*/
|
||||
private function _validate_query_tables($sql) {
|
||||
// Whitelist of allowed tables - users can only query these
|
||||
$allowed_tables = [
|
||||
$this->config->item('table_name'), // Main logbook table (e.g., TABLE_HRD_CONTACTS_V01)
|
||||
'station_profile',
|
||||
'dxcc_entities',
|
||||
'lotw_users',
|
||||
'queries'
|
||||
];
|
||||
|
||||
// Convert to lowercase for case-insensitive comparison
|
||||
$allowed_tables_lower = array_map('strtolower', $allowed_tables);
|
||||
$main_table_lower = strtolower($this->config->item('table_name'));
|
||||
|
||||
// Normalize the SQL: remove newlines and extra spaces for easier parsing
|
||||
$normalized_sql = preg_replace('/\s+/', ' ', trim($sql));
|
||||
|
||||
// Pattern 1: Check for UNION/INTO OUTFILE/LOAD FILE - these are always blocked
|
||||
if (preg_match('/\bunion\b.*?\bselect.*?\bfrom\s+(\w+)/i', $normalized_sql, $matches)) {
|
||||
$union_table = strtolower($matches[1]);
|
||||
if (!in_array($union_table, $allowed_tables_lower)) {
|
||||
log_message('error', "Search query blocked: UNION with unauthorized table - '$union_table'");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern 2: Extract all table names after FROM and JOIN keywords
|
||||
// This handles: FROM `table`, JOIN `table`, FROM table, JOIN table
|
||||
preg_match_all('/\b(?:FROM|JOIN)\s+`?(\w+)`?/i', $normalized_sql, $from_join_matches);
|
||||
$found_tables = $from_join_matches[1];
|
||||
|
||||
// Pattern 3: Extract table.column references that are NOT in the whitelist
|
||||
// This catches things like "users.password" or "admin.secret"
|
||||
preg_match_all('/(\w+)\.\w+/i', $normalized_sql, $column_refs);
|
||||
foreach ($column_refs[1] as $potential_table) {
|
||||
$potential_table_lower = strtolower($potential_table);
|
||||
// Only add if it's not a SQL keyword and not the main table
|
||||
$sql_keywords = ['select', 'where', 'order', 'group', 'having', 'limit', 'offset',
|
||||
'and', 'or', 'not', 'null', 'like', 'in', 'between', 'exists', 'case',
|
||||
'when', 'then', 'else', 'end', 'as', 'on', 'desc', 'asc', 'left', 'right', 'inner', 'outer'];
|
||||
if (!in_array($potential_table_lower, $sql_keywords) && $potential_table_lower !== $main_table_lower) {
|
||||
$found_tables[] = $potential_table;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all found tables are in whitelist
|
||||
$found_tables = array_unique($found_tables);
|
||||
foreach ($found_tables as $table) {
|
||||
if (empty($table)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table_lower = strtolower($table);
|
||||
|
||||
// Skip common SQL keywords that might match
|
||||
$sql_keywords = ['select', 'where', 'order', 'group', 'having', 'limit', 'offset',
|
||||
'and', 'or', 'not', 'null', 'like', 'in', 'between', 'exists', 'case',
|
||||
'when', 'then', 'else', 'end', 'as', 'on', 'desc', 'asc', 'left', 'right', 'inner', 'outer'];
|
||||
if (in_array($table_lower, $sql_keywords)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($table_lower, $allowed_tables_lower)) {
|
||||
log_message('error', "Search query blocked: unauthorized table access detected - '$table'");
|
||||
log_message('error', "Full query: $sql");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user