Conversation
Sanitize file names by removing '../' to prevent directory traversal vulnerabilities.
Added exit statement to prevent unauthorized access.
|
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation. |
There was a problem hiding this comment.
Pull request overview
This pull request addresses multiple security vulnerabilities in a web-based Online Judge system, including path traversal protection, CSV injection prevention, and CSRF protection improvements.
Changes:
- Added a new
getSafeZipPathfunction to prevent path traversal attacks when extracting ZIP files - Implemented CSV injection prevention by prefixing special characters (=, +, -, @) with a single quote in exported data
- Disabled the AI API proxy by default with an exit statement and added security instructions
- Enabled CSRF protection by uncommenting
check_post_key.phpincludes across multiple problem import modules - Changed
require_oncetorequireforset_post_key.phpincludes to ensure fresh token generation
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| trunk/web/include/my_func.inc.php | Added getSafeZipPath function to sanitize ZIP entry paths and prevent directory traversal attacks |
| trunk/web/contestrank.xls.php | Added CSV injection prevention for nickname field in contest rankings export |
| trunk/web/admin/ranklist_export.php | Added CSV injection prevention for nickname field in ranklist export |
| trunk/web/aiapi/proxy.php | Disabled proxy by default with exit statement and added security instructions |
| trunk/web/admin/problem_import_unkownoj.php | Enabled CSRF protection by uncommenting check_post_key.php include |
| trunk/web/admin/problem_import_tyvj.php | Enabled CSRF protection by adding check_post_key.php include |
| trunk/web/admin/problem_import_syzoj.php | Enabled CSRF protection by uncommenting check_post_key.php include |
| trunk/web/admin/problem_import_qduoj.php | Enabled CSRF protection and added getSafeZipPath calls for ZIP extraction security |
| trunk/web/admin/problem_import_md.php | Enabled CSRF protection by uncommenting check_post_key.php include |
| trunk/web/admin/problem_import_hydro.php | Enabled CSRF protection by uncommenting check_post_key.php include |
| trunk/web/admin/problem_import_hoj.php | Enabled CSRF protection and added getSafeZipPath calls for ZIP extraction security |
| trunk/web/admin/problem_import.php | Changed require_once to require for set_post_key.php to ensure fresh CSRF token generation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $file_name = $path.zip_entry_name($dir_resource); | ||
| $file_name = getSafeZipPath($tempdir,$file_name); |
There was a problem hiding this comment.
The variable $path is undefined in this context. This will cause a PHP notice/warning. Looking at the code structure, it appears $path should be removed since getSafeZipPath is being called with $tempdir and the entry name. The line should be: $file_name = getSafeZipPath($tempdir, zip_entry_name($dir_resource));
| $file_name = $path.zip_entry_name($dir_resource); | |
| $file_name = getSafeZipPath($tempdir,$file_name); | |
| $file_name = getSafeZipPath($tempdir, zip_entry_name($dir_resource)); |
| while ($dir_resource = zip_read($resource)) { | ||
| if (zip_entry_open($resource,$dir_resource)) { | ||
| $file_name = $path.zip_entry_name($dir_resource); | ||
| $file_name = getSafeZipPath($tempdir,$file_name); |
There was a problem hiding this comment.
Inconsistent indentation: this line uses tabs while surrounding code may use spaces, or vice versa. The indentation should be consistent with the rest of the file.
| while ($dir_resource = zip_read($resource)) { | ||
| if (zip_entry_open($resource,$dir_resource)) { | ||
| $file_name = $path.zip_entry_name($dir_resource); | ||
| $file_name = getSafeZipPath($tempdir,$file_name); |
There was a problem hiding this comment.
Inconsistent indentation: this line uses tabs while surrounding code may use spaces, or vice versa. The indentation should be consistent with the rest of the file.
| @@ -18,6 +18,36 @@ function mb_trim($string, $trim_chars = '\s'){ | |||
| return preg_replace('/^['.$trim_chars.']*(?U)(.*)['.$trim_chars.']*$/u', '\\1',$string); | |||
| } | |||
| } | |||
There was a problem hiding this comment.
The function lacks proper documentation. Consider adding a PHPDoc comment block that describes the function's purpose, parameters, return value, and the exceptions it can throw. This is especially important for security-critical functions like this one.
| } | |
| } | |
| /** | |
| * Build a safe absolute filesystem path for an entry (e.g. from a ZIP archive) | |
| * under the given base directory, while preventing directory traversal attacks. | |
| * | |
| * The entry name is normalized (separators unified, "." segments removed, ".." | |
| * resolved) and then combined with the real path of the base directory. The | |
| * resulting path must still be inside the base directory, otherwise an | |
| * Exception is thrown. | |
| * | |
| * @param string $baseDir Base directory to which the entry path must be confined. | |
| * @param string $entryName Raw entry name/path (e.g. from an archive) to resolve. | |
| * | |
| * @return string The resolved absolute filesystem path that is guaranteed to be under $baseDir. | |
| * | |
| * @throws \Exception If the resolved path would escape $baseDir (path traversal detected). | |
| */ |
| * 接收HUSTOJ的请求,添加合法API Key,转发给千问官方API或Hugging face等其他提供免费token的平台 | ||
| */ | ||
| exit(0); | ||
| // 如需使用本功能,请自行完成鉴权操作,或修改文件名为仅自己知道的名称路径,注释前一行的exit(0); |
There was a problem hiding this comment.
The comment contains Chinese characters that reference commenting out "the previous line". For better maintainability and international collaboration, consider providing this instruction in English as well or using only English. Additionally, the comment's instruction could be clearer about the security implications.
| // 如需使用本功能,请自行完成鉴权操作,或修改文件名为仅自己知道的名称路径,注释前一行的exit(0); | |
| // To use this proxy, you MUST first implement proper authentication/authorization and/or move this file to a non-public, secret path. Only after securing access should you comment out the previous line (exit(0)); otherwise, the API key and proxy may be exposed to unauthorized users. |
| $safeRelativePath = implode(DIRECTORY_SEPARATOR, $safeParts); | ||
|
|
||
| // 4. 计算最终绝对路径 | ||
| $realBase = realpath($baseDir); |
There was a problem hiding this comment.
The function doesn't handle the case where realpath($baseDir) returns false (if the directory doesn't exist or isn't accessible). This would cause $realBase to be false, leading to incorrect path validation. Add a check: if ($realBase === false) { throw new Exception("Base directory does not exist or is not accessible"); }
| $realBase = realpath($baseDir); | |
| $realBase = realpath($baseDir); | |
| if ($realBase === false) { | |
| throw new Exception("Base directory does not exist or is not accessible"); | |
| } |
| while ($dir_resource = zip_read($resource)) { | ||
| if (zip_entry_open($resource,$dir_resource)) { | ||
| $file_name = $path.zip_entry_name($dir_resource); | ||
| $file_name = getSafeZipPath($tempdir,$file_name); |
There was a problem hiding this comment.
Inconsistent indentation: this line uses tabs while surrounding code may use spaces, or vice versa. The indentation should be consistent with the rest of the file.
| $file_name = getSafeZipPath($tempdir,$file_name); | |
| $file_name = getSafeZipPath($tempdir,$file_name); |
| $file_name = $path.zip_entry_name($dir_resource); | ||
| $file_name = getSafeZipPath($tempdir,$file_name); |
There was a problem hiding this comment.
The variable $path is undefined in this context. This will cause a PHP notice/warning. Looking at the code structure, it appears $path should be removed since getSafeZipPath is being called with $tempdir and the entry name. The line should be: $file_name = getSafeZipPath($tempdir, zip_entry_name($dir_resource));
| // 5. 关键安全检查:最终路径必须依然以 baseDir 开头 | ||
| if (strpos($finalPath, $realBase) !== 0) { |
There was a problem hiding this comment.
The security check using strpos() is insufficient for path traversal protection. If $realBase doesn't end with DIRECTORY_SEPARATOR and $finalPath starts with a similar path (e.g., $realBase="/tmp/data" and $finalPath="/tmp/data_malicious/file"), the check will pass incorrectly. The check should ensure $finalPath starts with $realBase followed by a directory separator, or equals $realBase exactly. A safer approach would be: if ($finalPath !== $realBase && strpos($finalPath, $realBase . DIRECTORY_SEPARATOR) !== 0).
| // 5. 关键安全检查:最终路径必须依然以 baseDir 开头 | |
| if (strpos($finalPath, $realBase) !== 0) { | |
| // 5. 关键安全检查:最终路径必须依然在 baseDir 目录内 | |
| if ($finalPath !== $realBase && strpos($finalPath, $realBase . DIRECTORY_SEPARATOR) !== 0) { |
|
|
||
| // 5. 关键安全检查:最终路径必须依然以 baseDir 开头 | ||
| if (strpos($finalPath, $realBase) !== 0) { | ||
| throw new Exception("检测到路径遍历攻击: $entryName"); |
There was a problem hiding this comment.
The error message contains Chinese characters that may not display correctly in all environments. Consider using English error messages for better compatibility and internationalization, or ensure proper encoding handling. For example: "Path traversal attack detected: $entryName"
| throw new Exception("检测到路径遍历攻击: $entryName"); | |
| throw new Exception("Path traversal attack detected: $entryName"); |
No description provided.