1.修复上传漏洞和SQL注入漏洞-增强登录验证功能
This commit is contained in:
@@ -59,6 +59,13 @@ class Upload
|
||||
|
||||
public function setDriver(string $driver): self
|
||||
{
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $driver)) {
|
||||
throw new InvalidArgumentException(__('Driver %s not supported', [$driver]));
|
||||
}
|
||||
$allowed = $this->checkConfig($this->config['allowed_drivers'] ?? 'local');
|
||||
if ($allowed && !in_array(strtolower($driver), $allowed)) {
|
||||
throw new InvalidArgumentException(__('Driver %s not supported', [$driver]));
|
||||
}
|
||||
$this->driver['name'] = $driver;
|
||||
return $this;
|
||||
}
|
||||
@@ -79,11 +86,16 @@ class Upload
|
||||
|
||||
protected function resolveDriverClass(string $driver): string|false
|
||||
{
|
||||
if ($this->driver['namespace'] || str_contains($driver, '\\')) {
|
||||
$class = str_contains($driver, '\\') ? $driver : $this->driver['namespace'] . $this->studly($driver);
|
||||
if (class_exists($class)) {
|
||||
return $class;
|
||||
}
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $driver)) {
|
||||
return false;
|
||||
}
|
||||
$allowed = $this->checkConfig($this->config['allowed_drivers'] ?? 'local');
|
||||
if ($allowed && !in_array(strtolower($driver), $allowed)) {
|
||||
return false;
|
||||
}
|
||||
$class = $this->driver['namespace'] . $this->studly($driver);
|
||||
if (class_exists($class)) {
|
||||
return $class;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -181,6 +193,10 @@ class Upload
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
|
||||
$this->assertSafeFileName($this->fileInfo['name']);
|
||||
$this->assertNoMaliciousContent();
|
||||
$this->assertImageMime();
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $this->topic)) {
|
||||
throw new RuntimeException(__('Topic format error'));
|
||||
}
|
||||
@@ -257,4 +273,95 @@ class Upload
|
||||
}
|
||||
return $configItem ? explode(',', strtolower((string)$configItem)) : [];
|
||||
}
|
||||
|
||||
protected function getForbiddenSuffixes(): array
|
||||
{
|
||||
return $this->checkConfig($this->config['forbidden_suffixes'] ?? '');
|
||||
}
|
||||
|
||||
protected function assertSafeFileName(string $fileName): void
|
||||
{
|
||||
$forbidden = $this->getForbiddenSuffixes();
|
||||
if (!$forbidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parts = explode('.', strtolower($fileName));
|
||||
if (count($parts) < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if ($part === '') {
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
if ($index === count($parts) - 1) {
|
||||
continue;
|
||||
}
|
||||
if (in_array($part, $forbidden)) {
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
}
|
||||
|
||||
$suffix = $parts[count($parts) - 1];
|
||||
if (in_array($suffix, $forbidden)) {
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
}
|
||||
|
||||
protected function assertNoMaliciousContent(): void
|
||||
{
|
||||
$path = $this->file->getPathname();
|
||||
if (!is_file($path) || !is_readable($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$handle = fopen($path, 'rb');
|
||||
if (!$handle) {
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
$chunk = fread($handle, 8192);
|
||||
fclose($handle);
|
||||
if ($chunk === false || $chunk === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$patterns = [
|
||||
'/<\?php/i',
|
||||
'/<\?=/i',
|
||||
'/<\?(?!xml)/i',
|
||||
'/<%[@=]?/i',
|
||||
'/<script\b/i',
|
||||
'/\b(eval|assert|shell_exec|system|passthru|proc_open|popen|base64_decode)\s*\(/i',
|
||||
];
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $chunk)) {
|
||||
throw new RuntimeException(__('The uploaded file contains prohibited content'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function assertImageMime(): void
|
||||
{
|
||||
$imageSuffixes = ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'];
|
||||
if (!in_array($this->fileInfo['suffix'], $imageSuffixes, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$path = $this->file->getPathname();
|
||||
if (!is_file($path)) {
|
||||
throw new RuntimeException(__('The uploaded image file is not a valid image'));
|
||||
}
|
||||
|
||||
if (function_exists('finfo_open')) {
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
if ($finfo) {
|
||||
$detected = finfo_file($finfo, $path);
|
||||
finfo_close($finfo);
|
||||
if (!$detected || !str_starts_with(strtolower($detected), 'image/')) {
|
||||
throw new RuntimeException(__('The uploaded image file is not a valid image'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user