fix SQL injection: use parameterized query in login-discuz.php#1145
fix SQL injection: use parameterized query in login-discuz.php#1145
Conversation
- admin/problem_df_change.php: wrap hlist processing in braces and apply array_map intval - admin/contest_add.php: same fix for hlist bypass of intval protection
- Replace string interpolation '$user_id' in SQL with ? placeholder - Pass $user_id as bound parameter to pdo_query() - Fixes both the main query and the discuz_conn branch
There was a problem hiding this comment.
Pull request overview
This PR aims to mitigate SQL injection risks in the Discuz login integration and harden a couple of admin endpoints that build IN (...) clauses from request data.
Changes:
- Switch Discuz user lookup in
login-discuz.phpto a parameterized query (username = ?). - Sanitize comma-separated problem ID lists in admin actions by casting elements to integers before building
IN (...)SQL. - Minor refactor to guard parsing logic behind
isset($_POST['hlist'])inproblem_df_change.php.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| trunk/web/include/login-discuz.php | Uses a bound parameter for username to avoid SQL injection, but leaves a broken/unused legacy connection block. |
| trunk/web/admin/problem_df_change.php | Casts hlist elements to int before interpolating into IN (...). |
| trunk/web/admin/contest_add.php | Casts hlist elements to int before interpolating into IN (...) for updates. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if($discuz_conn){ | ||
| mysql_select_db($discuz_db,$discuz_conn); | ||
| $result=pdo_query($sql,$discuz_conn); | ||
| $result=pdo_query($sql, $user_id); |
There was a problem hiding this comment.
Inside the $discuz_conn block, mysql_select_db() does not affect pdo_query() (which uses the global PDO connection), and the second pdo_query($sql, $user_id) result is never applied to $row. This makes the block redundant and can cause Discuz login to fail if mysql_connect() fails even though the PDO query succeeds. Consider removing the legacy mysql_* connection entirely and rely on the parameterized pdo_query() result (or introduce a separate PDO connection for Discuz and refresh $row from that query).
There was a problem hiding this comment.
Done in commit 9226766. Removed the entire legacy mysql_connect() / mysql_select_db() block along with the unused host/port/user/pass variables and the redundant second pdo_query() call. The function now relies solely on the single parameterized pdo_query() result, with a null guard added to $row before the password comparison.
There was a problem hiding this comment.
This was already applied in commit 9226766 — the legacy mysql_connect() / mysql_select_db() block and all unused connection variables have been removed. The function now relies solely on the single parameterized pdo_query() result with a null guard on $row.
| $pieces = explode(",",$plist); | ||
| $pieces = array_unique($pieces); | ||
| if($pieces[0]=="")unset($pieces[0]); | ||
| // 安全修复:每个ID元素强制intval,防止SQL注入 | ||
| $plist = implode(",", array_map('intval', $pieces)); |
There was a problem hiding this comment.
array_map('intval', $pieces) will convert empty elements (e.g. input like "1,,2" or trailing commas) to 0, which then ends up in the IN ($plist) clause. It would be safer to trim/filter out empty strings and (optionally) drop non-positive IDs before imploding, and then run array_unique on the normalized integers to avoid duplicates reappearing after casting.
| $pieces = explode(",",$plist); | |
| $pieces = array_unique($pieces); | |
| if($pieces[0]=="")unset($pieces[0]); | |
| // 安全修复:每个ID元素强制intval,防止SQL注入 | |
| $plist = implode(",", array_map('intval', $pieces)); | |
| $pieces = explode(",", $plist); | |
| // Trim each element | |
| $pieces = array_map('trim', $pieces); | |
| // Keep only non-empty, digit-only, positive IDs | |
| $pieces = array_filter($pieces, function ($v) { | |
| return $v !== '' && ctype_digit($v) && (int)$v > 0; | |
| }); | |
| // Normalize to integers and remove duplicates | |
| $intPieces = array_unique(array_map('intval', $pieces), SORT_NUMERIC); | |
| if (empty($intPieces)) { | |
| $plist = ''; | |
| } else { | |
| // 安全修复:每个ID元素强制intval,防止SQL注入 | |
| $plist = implode(",", $intPieces); | |
| } |
| $pieces = explode(",",$plist); | ||
| $pieces = array_unique($pieces); | ||
| if($pieces[0]=="") unset($pieces[0]); | ||
| $plist=implode(",",$pieces); | ||
| // 安全修复:每个ID元素强制intval,防止SQL注入 | ||
| $plist = implode(",", array_map('intval', $pieces)); |
There was a problem hiding this comment.
array_map('intval', $pieces) can turn empty list elements into 0 (e.g. "1000,,1002"), which changes behavior from a SQL syntax error to including 0 in the IN (...) list. Consider filtering out empty strings and removing 0/negative IDs before building $plist, and de-duplicating after integer normalization.
| if(isset($_POST['hlist'])){ | ||
| $plist = trim($_POST['hlist']); | ||
| $pieces = explode(",",$plist); | ||
| $pieces = array_unique($pieces); | ||
| if($pieces[0]=="")unset($pieces[0]); | ||
| // 安全修复:每个ID元素强制intval,防止SQL注入 | ||
| $plist = implode(",", array_map('intval', $pieces)); | ||
| } |
There was a problem hiding this comment.
The PR title/description focus on include/login-discuz.php, but this PR also changes SQL-related input handling in admin pages (problem_df_change.php, contest_add.php). Please update the PR description/title to reflect these additional security fixes (or split into separate PRs) so reviewers can assess scope and risk accurately.
Fix SQL Injection in login-discuz.php
问题
include/login-discuz.php第17行,$user_id直接拼入 SQL 字符串:修复
改用参数化查询:
注:仅当
$OJ_LOGIN_MOD="discuz"时生效,默认配置为"hustoj"不受影响。