news 2026/7/6 9:43:42

Web安全实战:从DCRCMS漏洞看文件上传漏洞的多层次防御体系构建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Web安全实战:从DCRCMS漏洞看文件上传漏洞的多层次防御体系构建

1. 项目概述:为什么文件上传漏洞是Web安全的“阿喀琉斯之踵”

在Web应用安全领域,文件上传功能一直是个高危地带,它就像系统对外开放的一个“后门”,一旦守卫不严,攻击者就能长驱直入。DCRCMS 1.1.5版本曝出的那个文件上传漏洞(CNVD-2020-27175),就是一个教科书级别的反面案例。这个漏洞的可怕之处在于,它并非什么高深莫测的0day,而是一个由开发者疏忽导致的、可以被轻易利用的“低垂果实”。攻击者无需复杂的认证绕过,就能直接上传一个Webshell,瞬间将网站服务器变成自己的“肉鸡”,数据泄露、服务中断、甚至成为攻击跳板,后果不堪设想。

我处理过不少类似的应急响应,很多开发者,甚至是一些经验不算浅的运维,对文件上传功能的风险认知都停留在“检查一下文件后缀”的层面。这远远不够。DCRCMS的这个漏洞,恰恰就击穿了这种简单的防御思维。今天,我们不打算做一次简单的漏洞复现演示——那种内容网上已经很多了。我想从一个防御者的视角,和你深入聊聊,当我们面对一个像DCRCMS这样存在历史漏洞的系统,或者我们自己开发的文件上传功能时,应该如何系统性地构建防御体系,把这道“后门”焊死。这不仅仅是修复一个已知漏洞,更是建立一套面对未知攻击的安全思维和实战能力。无论你是正在使用DCRCMS的站长、负责安全加固的运维工程师,还是想深入理解文件上传漏洞防御的开发者,这篇指南都将提供从漏洞原理分析到多层次加固的完整路线图。

2. 漏洞深度剖析:DCRCMS文件上传漏洞的“病根”在哪里

要有效防御,必须先透彻理解攻击是如何发生的。DCRCMS 1.1.5版本的文件上传漏洞,其核心“病根”在于服务端验证逻辑的严重缺失与设计缺陷。我们通常说的“文件上传漏洞”,攻击者最终目标是上传一个可被服务器执行的脚本文件(如PHP、JSP、ASP等),从而获得命令执行能力。DCRCMS的这个漏洞,几乎为攻击者铺平了所有道路。

2.1 漏洞触发路径与原理还原

根据公开的漏洞详情和分析,攻击路径异常清晰。通常,一个安全的文件上传模块应该包含多层校验:前端校验(用户体验)、服务端MIME类型校验、服务端文件扩展名校验、服务端文件内容校验,甚至文件重命名。而DCRCMS 1.1.5版本在关键的服务端校验环节出现了致命疏漏。

攻击者很可能直接绕过了前端的所有JavaScript校验(这本身是应该的,前端校验仅用于提升体验,绝非安全屏障),将一个伪装好的恶意文件(例如一个图片马,将PHP代码嵌入到图片的EXIF信息或文件末尾)直接POST到文件上传接口。服务端代码在接收文件后,可能只进行了非常简单的、基于黑名单的扩展名检查,或者检查逻辑可以被轻易绕过。例如,代码可能只检查文件名中是否包含“.php”字符串,但攻击者可以使用“.php.”、“.php ”(空格)、“.php%00.jpg”(利用截断漏洞,取决于老旧PHP版本)或“.phtml”等变种来绕过。更严重的是,系统可能根本没有对文件的内容进行任何检测,仅凭用户上传时提供的Content-Type(如image/jpeg)就相信了文件的真实性,这完全是“掩耳盗铃”。

注意:很多初级开发会依赖$_FILES[‘file’][‘type’]进行类型判断,但这个值完全由浏览器端控制,可以被攻击者随意篡改,绝对不可信。必须使用服务端的文件头检测函数(如finfo_file())来获取真实的MIME类型。

漏洞的另一个关键点在于文件存储路径和访问权限。即使文件被上传,如果它被存储在一个无法通过Web直接访问的目录,或者其执行权限被正确限制,危害也会大大降低。但在此漏洞场景下,上传的文件很可能被直接存放到Web根目录(或子目录)下,并且保留了原始的文件名和扩展名,使得攻击者能够通过构造的URL直接访问并执行这个Webshell,从而完成漏洞利用链的最后一环。

2.2 从漏洞看常见安全误区

DCRCMS这个案例暴露了几个普遍的安全误区:

  1. 过度依赖前端验证:将安全责任交给浏览器,是最大的安全幻觉。
  2. 使用黑名单而非白名单:试图列出所有危险的后缀(如php, asp, jsp, exe等)是徒劳的,总有漏网之鱼或新的变种。安全的原则是“默认拒绝”,只允许明确安全的类型。
  3. 信任用户提交的任何元数据:包括文件名、MIME类型、文件大小(需在服务端再次校验)等。
  4. 缺乏文件内容检测:无法识别伪装成图片的脚本文件。
  5. 不当的文件存储与访问控制:将用户上传的文件视为静态资源,并存放在Web可执行目录下。

理解这些,我们就能有的放矢地构建防御体系,而不是盲目地打补丁。

3. 构建多层次文件上传安全防御体系

修复一个特定漏洞是治标,建立一套防御体系才是治本。针对文件上传功能,我们需要构建一个从外到内、层层递进的“纵深防御”体系。这套体系可以概括为六个关键层级,我将结合PHP语言的示例进行说明,其原理适用于所有Web技术栈。

3.1 第一层:严格的扩展名与类型白名单校验

这是最基础、也最重要的一关。核心原则是:只允许,不禁止

具体操作:

  1. 定义一个明确的白名单数组,只包含业务绝对需要的文件类型。例如,如果是一个头像上传功能,白名单可以设为[‘jpg’, ‘jpeg’, ‘png’, ‘gif’]
  2. 获取文件扩展名时,不要简单地用strrchr()找最后一个点,而要使用pathinfo($filename, PATHINFO_EXTENSION),并将其转换为小写strtolower(),以避免大小写绕过(如.Php)。
  3. 服务端MIME类型校验必须使用可靠的方式。在PHP中,推荐使用Fileinfo扩展。
// 定义白名单 $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif']; $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif']; // 获取并处理扩展名 $extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)); if (!in_array($extension, $allowedExtensions)) { die('文件类型不被允许。'); } // 使用Fileinfo获取真实MIME类型 $finfo = finfo_open(FILEINFO_MIME_TYPE); $realMimeType = finfo_file($finfo, $_FILES['file']['tmp_name']); finfo_close($finfo); if (!in_array($realMimeType, $allowedMimeTypes)) { die('文件MIME类型不匹配。'); }

实操心得:白名单列表应该尽可能收紧。曾经有一个案例,允许上传‘doc’, ‘docx’,结果攻击者上传了包含恶意宏的docm文件。如果业务不需要,就不要开放。同时,MIME类型白名单应与扩展名白名单对应,进行双重校验。

3.2 第二层:文件内容与二进制头检测

这是防御“图片马”等伪装文件的关键。攻击者可以将PHP代码附加到一个正常图片的末尾,文件扩展名和MIME类型检测都显示为图片,但一旦被当作PHP执行,后面的代码就会生效。

具体操作:

  1. 检查文件头(Magic Number):每种文件格式在文件开头都有特定的二进制签名。例如,JPEGFF D8 FF开头,PNG89 50 4E 47开头。我们可以通过读取文件前几个字节进行验证。
  2. 使用getimagesize()函数:对于图片文件,PHP的getimagesize()函数会尝试解析图片数据,如果文件不是有效的图片,它会返回false。这是一个快速有效的辅助手段。
  3. 进行病毒/恶意代码扫描:对于企业级应用,可以集成ClamAV等开源杀毒引擎的接口,对上传的文件进行静态扫描。
// 接上一段代码 // 使用getimagesize进行二次图片验证 if (in_array($extension, ['jpg','jpeg','png','gif'])) { $imageInfo = @getimagesize($_FILES['file']['tmp_name']); if ($imageInfo === false) { die('上传的文件不是有效的图片。'); } // 可选:进一步检查图片宽高,防止超小或超大的恶意文件 if ($imageInfo[0] < 10 || $imageInfo[1] < 10) { die('图片尺寸异常。'); } } // 手动检查文件头示例 (PNG) if ($extension === 'png') { $fileHandle = fopen($_FILES['file']['tmp_name'], 'rb'); $header = fread($fileHandle, 8); fclose($fileHandle); if ($header !== "\x89PNG\r\n\x1a\n") { // PNG文件头 die('PNG文件头校验失败。'); } }

3.3 第三层:安全的文件重命名与存储策略

永远不要使用用户上传的文件名!这不仅是安全要求,也能避免中文、空格等字符带来的问题。

具体操作:

  1. 生成随机文件名:使用uniqid()md5()(时间+随机数)或更安全的random_bytes()生成一个唯一的字符串作为文件名。
  2. 强制使用白名单内的扩展名:将生成的文件名与我们之前校验通过的后缀拼接。
  3. 使用安全的存储路径
    • 理想情况:将文件存储在Web根目录之外。通过一个专门的脚本(如download.php?id=xxx)来读取和输出文件。这样,即使上传了脚本文件,也无法直接通过URL访问执行。
    • 折中方案:如果必须存储在Web可访问目录(如CDN需求),则务必将其放在一个独立的、配置了严格权限的子目录中。并通过配置Web服务器(如Nginx/Apache),禁止该目录执行脚本。
// 生成安全文件名并存储 $newFileName = bin2hex(random_bytes(16)) . '.' . $extension; // 例如:7a3b8c9d0e1f2a3b4c5d6e7f8a9b0c1d.jpg $uploadDir = '/var/www/uploads/images/'; // 建议配置在Web根目录外,如 /var/www/upload/ $destination = $uploadDir . $newFileName; if (!move_uploaded_file($_FILES['file']['tmp_name'], $destination)) { die('文件移动失败。'); } // 返回给前端的是由我们控制的文件名或文件ID $fileUrl = '/file_proxy.php?hash=' . $newFileName; // 通过代理脚本访问

Nginx配置示例(禁止指定目录执行PHP):

location ~ ^/uploads/.*\.(php|php5|jsp|asp)$ { deny all; }

3.4 第四层:服务器与运行环境加固

应用层防御之上,是系统层的最后屏障。

  1. 设置上传目录无执行权限:在操作系统层面,使用chmod命令将上传目录的权限设置为755(所有者可读可写可执行,其他用户只读不可执行),并确保文件所属用户是Web服务器用户(如www-datanginx)。
    chown -R www-data:www-data /var/www/uploads/ chmod -R 755 /var/www/uploads/ # 或者更严格地,只给目录执行权限,文件只给读写权限 find /var/www/uploads/ -type f -exec chmod 644 {} \;
  2. 配置PHP安全选项:在php.ini中,可以禁用危险函数,并限制文件操作。
    disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source open_basedir = /var/www/html:/var/www/uploads/ # 限制PHP可访问的目录
  3. 使用容器或沙盒环境:对于高安全要求场景,可以考虑将文件上传和处理功能部署在一个独立的、权限受到严格限制的容器或沙盒环境中,即使被攻破,影响范围也有限。

3.5 第五层:流量监控与入侵检测

防御不仅要“防”,还要“察”。建立监控机制,以便在发生攻击时能快速响应。

  1. 日志记录:详细记录每一次文件上传操作,包括时间、IP、用户ID、原始文件名、最终存储路径、文件大小、MD5等。这些日志是事后审计和追踪攻击源的宝贵资料。
  2. 异常行为检测:监控上传目录。如果短时间内出现大量上传请求、上传文件大小异常、或文件名具有明显攻击特征(如包含cmdshell等关键字),应触发告警。
  3. Web应用防火墙(WAF):部署WAF,可以拦截大量已知的文件上传攻击payload,为应用本身提供一个缓冲层。

3.6 第六层:业务逻辑与权限校验

这是最容易被忽略的一层。文件上传功能必须在正确的业务上下文和用户权限下进行。

  1. 会话与身份验证:确保上传接口必须携带有效的、经过认证的用户会话。防止未授权访问。
  2. CSRF防护:为上传表单添加CSRF Token,防止跨站请求伪造攻击诱导用户上传恶意文件。
  3. 上传频率与配额限制:对单个用户或IP在单位时间内的上传次数、总文件大小进行限制,防止攻击者通过海量上传进行DoS攻击或模糊测试。
  4. 文件内容合规性检查(如图片):对于头像等图片,可能还需要进行鉴黄、鉴暴恐等AI内容审核,这属于业务安全范畴。

4. 针对DCRCMS漏洞的专项加固实操步骤

假设我们现在需要对一个正在运行的、可能存在类似漏洞的DCRCMS(或任何老旧CMS)进行紧急加固,可以按照以下步骤操作,这些步骤也适用于自查。

4.1 第一步:漏洞定位与代码审计

  1. 定位上传功能代码:在CMS目录中,全局搜索包含uploadfilemove_uploaded_file$_FILES等关键词的文件。常见的路径可能在/admin//include/或专门的/upload/模块下。
  2. 审计关键代码:找到处理上传的PHP文件(例如upload.phpfilemanager.php)。重点检查:
    • 是否存在任何服务端校验?(找in_arraypathinfofinfo_file等函数)
    • 校验逻辑是黑名单还是白名单?
    • 文件名如何处理?是直接使用$_FILES[‘file’][‘name’],还是经过了重命名?
    • 文件最终存储在哪里?路径是否在Web目录下?
  3. 模拟测试:在测试环境中,尝试上传各种畸形文件(如test.php.jpgtest.jpg.php、包含PHP代码的图片马等),观察系统行为。

4.2 第二步:实施紧急补丁

如果发现代码中校验缺失或薄弱,应立即制作补丁。不要直接修改核心文件,建议以下面两种方式之一进行:

方案A:在入口文件前置拦截(快速止血)在CMS的公共入口文件(如index.phpadmin/index.php)的顶部,添加一个全局的上传请求过滤器。

// 放在入口文件最前面 if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES)) { foreach ($_FILES as $file) { if ($file['error'] !== UPLOAD_ERR_OK) continue; $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); $allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx']; // 根据业务定义 if (!in_array($extension, $allowed)) { // 记录日志并拒绝 error_log("非法文件上传尝试: " . $file['name'] . " from IP: " . $_SERVER['REMOTE_ADDR']); die('Security Alert: File type not allowed.'); } // 可以在此处添加更严格的MIME类型检查 } }

方案B:修补具体上传文件(根治)直接修改找到的上传处理文件。将前面章节提到的“白名单校验”、“文件内容检测”、“安全重命名”三段核心代码,替换掉原有的脆弱逻辑。这是最推荐的方式。

4.3 第三步:服务器环境加固

  1. 立即修改上传目录权限
    # 找到DCRCMS的上传目录,通常在 /uploads/ 或 /data/upload/ find /path/to/dcrcms -type d -name "upload" -o -name "uploads" # 假设路径是 /var/www/html/dcrcms/uploads/ chmod -R 755 /var/www/html/dcrcms/uploads/ find /var/www/html/dcrcms/uploads/ -type f -exec chmod 644 {} \;
  2. 配置Nginx/Apache禁止执行脚本:如上文所述,在虚拟主机配置中添加针对上传目录的location规则,禁止执行PHP等脚本。
  3. 审查并清理已有文件:这是一个高风险操作,但必须做。列出上传目录中的所有文件,重点筛查.php,.phtml,.jsp,.asp,.asa,.cer等可执行后缀的文件,以及大小异常、创建时间异常的图片文件。可以使用find命令结合file命令进行粗略检查。
    find /var/www/html/dcrcms/uploads/ -type f -name "*.php" # 查找所有php文件 # 对于图片文件,可以用file命令检查实际类型 find /var/www/html/dcrcms/uploads/ -type f -name "*.jpg" -exec file {} \; | grep -v "JPEG image"

4.4 第四步:验证与监控

  1. 全面测试:修补后,在测试环境进行完整的文件上传功能测试,确保正常文件能上传,各种恶意文件能被拦截。
  2. 部署监控:在上传接口和上传目录部署监控。例如,使用inotifywait监控上传目录的新增文件,并记录日志。
    # 简单的inotify监控示例 inotifywait -m /var/www/html/dcrcms/uploads/ -e create | while read path action file; do echo "$(date): $file was $action in $path" >> /var/log/upload_monitor.log done
  3. 更新与跟进:关注DCRCMS官方是否有发布安全更新。如果这是开源系统,考虑将你的安全补丁提交给社区。

5. 常见问题排查与实战技巧实录

在实际加固和应急响应过程中,你会遇到各种各样的问题。这里记录了几个典型场景和我的处理思路。

5.1 问题一:修补后,网站用户反馈“无法上传图片”

  • 排查思路
    1. 检查错误日志:第一时间查看PHP错误日志(/var/log/php-fpm/error.log或 Apache的error.log)和Web服务器错误日志。里面通常会直接报出语法错误、权限拒绝等具体信息。
    2. 校验逻辑过于严格:检查你添加的白名单是否遗漏了业务需要的格式(比如漏了webp)。检查MIME类型列表是否与扩展名完全匹配(image/jpeg对应jpgjpeg)。
    3. 权限问题move_uploaded_file()失败,很可能是目标目录的权限不对。确保Web服务器用户(如www-data)对目标上传目录有写入权限。使用ls -la命令查看目录权限和所属用户/组。
    4. 临时文件问题:确保php.iniupload_tmp_dir指定的临时目录存在且可写。
  • 解决步骤
    1. 根据错误日志定位问题。
    2. 如果是权限问题:chown -R www-data:www-data /path/to/upload_dir
    3. 如果是白名单问题:修正白名单数组。
    4. 在测试环境充分验证后再上线。

5.2 问题二:攻击者上传了.htaccess文件覆盖了我们的配置

  • 风险:在Apache服务器中,.htaccess文件可以覆盖目录级别的配置。攻击者可能上传一个包含AddType application/x-httpd-php .jpg.htaccess文件,强制将jpg文件当作PHP执行,从而绕过所有后缀检查。
  • 防御技巧
    1. 在白名单中明确排除htaccess:虽然它没有后缀,但文件名固定。
    2. 服务器配置中禁止覆盖:在Apache主配置(httpd.conf或虚拟主机配置)中,针对上传目录设置AllowOverride None,彻底禁用.htaccess
      <Directory "/var/www/html/uploads/"> AllowOverride None Require all granted </Directory>
    3. 文件重命名时强制添加后缀:确保存储的文件名始终包含白名单内的后缀,即使原始文件没有后缀或后缀不合法。

5.3 问题三:如何检测已存在的Webshell?

  • 手动排查技巧
    • 查找最近修改的文件find /var/www/html -type f -name “*.php” -mtime -1查找一天内修改过的PHP文件。
    • 查找特征代码:使用grep搜索常见Webshell函数和特征码。
      grep -r “eval($_POST” /var/www/html # 查找一句话木马 grep -r “base64_decode” /var/www/html # 查找可能经过编码的恶意代码 grep -r “system(” /var/www/html # 查找命令执行函数
    • 检查文件大小和日期:对比正常文件,Webshell通常体积较小,且创建/修改时间可能集中在一个异常时间点。
  • 自动化工具推荐
    • ClamAV:开源杀毒引擎,可以扫描整个网站目录。
    • RIPS:一款开源的PHP静态代码分析工具,专门用于检测漏洞和Webshell。
    • 云盾、安全狗等服务器安全软件:它们通常具备Webshell查杀功能。

5.4 问题四:业务需要上传非图片文件(如PDF、Word),如何保证安全?

  • 核心思路:白名单依然是最重要的。将pdf,doc,docx等加入扩展名和MIME类型白名单。
  • 额外风险:这些文档格式可能包含宏(如DOCM)、JavaScript(PDF)或隐藏的链接,存在钓鱼或漏洞利用风险。
  • 加固措施
    1. 隔离存储与访问:强烈建议将这些文件存储在Web不可直接访问的目录,通过一个经过严格认证和授权的下载脚本(download.php?fileid=xxx)来提供下载。在脚本中,可以再次校验用户权限、记录下载日志。
    2. 内容安全检查:对于企业级应用,可以考虑使用商业或开源的文档内容安全检查服务,在文件上传后对其进行解析和风险扫描。
    3. 预览转换:对于可读文档,一个更安全的做法是,在后端将其转换成安全的格式(如将PDF/Word转换成图片或HTML)再提供给用户预览,原始文件则加密存储。这彻底杜绝了文件本身携带恶意代码被执行的风险。

文件上传漏洞的防御是一场持久战,没有一劳永逸的银弹。DCRCMS的案例给我们敲响了警钟,但也提供了一个绝佳的学习样本。真正的安全,源于对每一行代码的审慎,对每一个用户输入的不信任,以及层层设防的纵深防御思维。从我个人的经验来看,很多漏洞的根源不在于技术有多难,而在于开发者是否具备基本的安全意识和编码习惯。把文中的这些检查点变成你开发文件上传功能时的“肌肉记忆”,才能从根本上守住这道关键防线。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/6 9:43:39

Java电商后端实战:SpringBoot实现小米商城架构,含Redis高并发秒杀方案

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;基于SpringBoot搭建的完整电商后端系统&#xff0c;真实复刻小米商城核心业务逻辑&#xff0c;支持与标准Vue前端分离部署。功能覆盖商品CRUD、用户注册登录、购物车增删改查、订单生成与状态管理、微信/支付宝…

作者头像 李华
网站建设 2026/7/6 9:39:43

基于视觉语言模型的零代码GUI自动化:从原理到实战应用

1. 项目概述&#xff1a;当AI“看见”你的屏幕 想象一下&#xff0c;你每天上班要重复登录十几个内部系统&#xff0c;手动填写表单、点击按钮、导出报表。或者&#xff0c;你是一个软件测试工程师&#xff0c;面对一个界面元素ID经常变动的Web应用&#xff0c;维护传统的基于坐…

作者头像 李华
网站建设 2026/7/6 9:36:44

Elixir Web服务安全加固:Bandit服务器配置与防护实践

1. 项目概述&#xff1a;为什么Elixir开发者需要关注Bandit的安全&#xff1f;如果你正在用Elixir构建Web服务&#xff0c;无论是Phoenix应用还是独立的HTTP接口&#xff0c;你大概率听说过或已经在用Bandit。这个纯Elixir实现的HTTP服务器&#xff0c;凭借其卓越的性能——在某…

作者头像 李华
网站建设 2026/7/6 9:36:21

从V8漏洞到实战利用:解析Electron应用沙箱逃逸与WDAC绕过技术

1. 项目概述&#xff1a;从“黑盒”到“白盒”的浏览器漏洞利用之路 “浏览器漏洞利用”这个词&#xff0c;对于很多刚接触安全研究的朋友来说&#xff0c;既神秘又令人望而生畏。它听起来像是顶级黑客的专属领域&#xff0c;充斥着复杂的数学、晦涩的内存布局和难以捉摸的代码…

作者头像 李华
网站建设 2026/7/6 9:34:26

从IDOR到拖库:一次AI招聘平台越权漏洞链的深度剖析

1. 项目概述&#xff1a;一次由越权查询引发的连锁反应 最近在复盘一个挺有意思的案例&#xff0c;一个AI招聘平台&#xff0c;从一个小小的越权查询漏洞开始&#xff0c;最终演变成了一场波及大量敏感数据的拖库攻击。泄露的数据里&#xff0c;不仅有常规的姓名、电话、邮箱&a…

作者头像 李华
网站建设 2026/7/6 9:32:40

Python 自动化图形推理:OpenCV 模拟 5 类规律识别算法

Python 自动化图形推理&#xff1a;OpenCV 模拟 5 类规律识别算法在数字图像处理领域&#xff0c;图形规律识别一直是计算机视觉的经典应用场景。传统人工解题方式效率低下且容易出错&#xff0c;而借助 OpenCV 和 NumPy 的强大功能&#xff0c;我们可以将这一过程完全自动化。…

作者头像 李华