DVWA从入门到精通(七):Insecure CAPTCHA(不安全的验证码)
摘要本文是《DVWA从入门到精通》系列的第七篇带你全面掌握Insecure CAPTCHA不安全的验证码模块的攻防全流程。从CAPTCHA验证码的设计初衷出发逐步讲解Low、Medium、High三个级别的逻辑漏洞与攻击手法并深入探讨Impossible级别的终极防御方案。文章包含两步验证流程的绕过、step参数篡改、passed_captcha参数伪造、User-Agent欺骗以及reCAPTCHA后门利用等高阶技术让你真正做到“知其然更知其所以然”。一、什么是CAPTCHA1.1 CAPTCHA的基本概念CAPTCHA是Completely Automated Public Turing Test to Tell Computers and Humans Apart的缩写中文意思是“全自动区分计算机和人类的图灵测试”。简单来说CAPTCHA就是一种用来区分用户是真人还是机器的自动化程序。用一个生活化的例子来理解想象你在一个演唱会门口排队入场保安问你“今天星期几”这个问题对人类来说太简单了但对于一个没有“星期几”概念的机器人来说它无法回答。CAPTCHA验证码就扮演着这个“保安”的角色——它设计一个对人类来说容易、但对计算机来说困难的“考题”从而区分当前访问者是人类还是机器人。从技术角度来看CAPTCHA的典型工作流程是服务器生成一个随机验证码扭曲的文字、图片点选、数学题等服务器将验证码以图片或问题的形式展示给用户用户输入看到的内容或回答问题服务器验证用户输入是否与正确答案匹配匹配则通过验证不匹配则拒绝1.2 CAPTCHA的作用CAPTCHA在Web安全中扮演着重要角色应用场景说明防止暴力破解阻止自动化工具对登录接口进行大量尝试防止刷单/刷票阻止机器人在电商平台恶意下单或投票防止垃圾注册阻止自动化脚本批量注册账号防止评论灌水阻止机器人在论坛/博客中大量发布垃圾评论二、什么是Insecure CAPTCHA漏洞2.1 漏洞的核心本质Insecure CAPTCHA不安全的验证码指的并不是验证码API本身存在漏洞而是指在使用验证码的过程中由于验证流程设计不当使得攻击者能够绕过验证码的安全验证。用一个生活化的例子来理解回到演唱会门口的例子。保安问“今天星期几”你回答了“星期三”保安说“答对了你进去吧”。然后你进去了。但问题是——这个保安只在你进场的时候问一次。如果你出来后再进去保安不再问问题了直接放行。更糟糕的是一个没买到票的人发现了这个规律他只需要在门口假装自己已经回答过问题保安就放他进去了。Insecure CAPTCHA漏洞就是这个道理——服务器只在流程的某一步检查验证码但后续步骤不再验证。攻击者可以通过直接跳到后续步骤来绕过验证码。2.2 漏洞的典型特征Insecure CAPTCHA漏洞通常具有以下特征特征说明流程分裂验证码验证和核心操作分为两个独立的步骤状态参数可控用于标识“已验证”状态的参数由客户端提交缺乏会话绑定验证结果没有与会话绑定可以被伪造逻辑信任错误服务器无条件信任客户端声称的“已验证”状态2.3 模块功能介绍在DVWA的Insecure CAPTCHA模块中功能是修改当前用户的密码。页面包含新密码输入框确认密码输入框reCAPTCHA验证码区域由Google提供三、准备工作3.1 靶场环境确保DVWA已部署并正常运行访问地址http://你的服务器IP/dvwa/login.php使用admin/password登录3.2 reCAPTCHA密钥配置DVWA的Insecure CAPTCHA模块使用Google的reCAPTCHA服务。在开始实验之前需要配置reCAPTCHA的密钥。如果未配置密钥页面会报错提示找不到验证码密钥。配置方法访问Google reCAPTCHA管理后台https://www.google.com/recaptcha/admin/create注册一个新的reCAPTCHA站点选择reCAPTCHA v2类型Domains填写你的靶机IP获取site key公钥和secret key私钥编辑DVWA的配置文件/xp/www/dvwa/config/config.inc.php填入密钥$_DVWA[ recaptcha_public_key ] 你的公钥; $_DVWA[ recaptcha_private_key ] 你的私钥;3.3 必备工具工具用途浏览器Chrome/Firefox访问靶场F12开发者工具Burp Suite抓包分析、修改请求参数四、Low级别流程分裂的“致命漏洞”4.1 安全级别设置将DVWA Security设置为Low级别然后进入Insecure CAPTCHA模块。4.2 界面观察页面上方显示“Password Reset”表单包含New password新密码Confirm new password确认新密码reCAPTCHA验证码区域4.3 源码分析查看Low级别的核心代码?php if( isset( $_POST[ Change ] ) ( $_POST[ step ] 1 ) ) { // Hide the CAPTCHA form $hide_form true; // Get input $pass_new $_POST[ password_new ]; $pass_conf $_POST[ password_conf ]; // Check CAPTCHA from 3rd party $resp recaptcha_check_answer( $_DVWA[ recaptcha_private_key], $_POST[g-recaptcha-response] ); // Did the CAPTCHA fail? if( !$resp ) { // What happens when the CAPTCHA was entered incorrectly $html . prebr /The CAPTCHA was incorrect. Please try again./pre; $hide_form false; return; } else { // CAPTCHA was correct. Do both new passwords match? if( $pass_new $pass_conf ) { // Show next stage for the user echo prebr /You passed the CAPTCHA! Click the button to confirm your changes.br //pre form action\#\ method\POST\ input type\hidden\ name\step\ value\2\ / input type\hidden\ name\password_new\ value\{$pass_new}\ / input type\hidden\ name\password_conf\ value\{$pass_conf}\ / input type\submit\ name\Change\ value\Change\ / /form; } else { // Both new passwords do not match. $html . preBoth passwords must match./pre; $hide_form false; } } } if( isset( $_POST[ Change ] ) ( $_POST[ step ] 2 ) ) { // Hide the CAPTCHA form $hide_form true; // Get input $pass_new $_POST[ password_new ]; $pass_conf $_POST[ password_conf ]; // Check to see if both password match if( $pass_new $pass_conf ) { // They do! $pass_new ((isset($GLOBALS[___mysqli_ston]) is_object($GLOBALS[___mysqli_ston])) ? mysqli_real_escape_string($GLOBALS[___mysqli_ston], $pass_new ) : ((trigger_error([MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work., E_USER_ERROR)) ? : )); $pass_new md5( $pass_new ); // Update database $insert UPDATE users SET password $pass_new WHERE user . dvwaCurrentUser() . ;; $result mysqli_query($GLOBALS[___mysqli_ston], $insert ) or die( pre . ((is_object($GLOBALS[___mysqli_ston])) ? mysqli_error($GLOBALS[___mysqli_ston]) : (($___mysqli_res mysqli_connect_error()) ? $___mysqli_res : false)) . /pre ); // Feedback for the end user echo prePassword Changed./pre; } else { // Issue with the passwords matching echo prePasswords did not match./pre; $hide_form false; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } ?这段代码存在致命的逻辑漏洞缺陷说明流程分为两步第一步验证验证码第二步修改密码状态参数可控服务器仅通过step参数判断用户是否已通过验证第二步无验证step2的代码块中没有验证码检查信任客户端服务器无条件信任客户端提交的step值4.4 攻击方法篡改step参数绕过验证码Low级别的核心漏洞在于step参数完全由客户端控制。攻击者可以直接将step从1修改为2跳过验证码验证。攻击步骤第一步正常填写表单在页面上输入新密码如hacker123和确认密码然后点击提交。第二步使用Burp Suite抓包Burp Suite会拦截到如下请求注意请求中若无step参数$_POST[step]为NULLLow 级代码存在两个独立if判断第一段要求$_POST[step] 1第二段改密代码要求$_POST[step] 2。NULL既不等于1也不等于2两个判断均无法触发不会执行密码修改逻辑。 正常前端抓包数据包携带step1password_newhacker123password_confhacker123ChangeChange仅会进入验证码校验逻辑无法直接修改密码想要绕过验证码执行改密需手动构造step2的 POST 请求。第三步修改step2参数第四步放行请求点击“Forward”放行请求服务器直接执行第二步的密码修改逻辑完全跳过了验证码验证。第五步验证结果页面显示“Password Changed”密码已成功修改为hacker123。4.5 Low级别总结缺陷说明流程分裂为两步验证与操作分离step参数可控攻击者可篡改第二步无验证直接执行密码修改无CSRF Token可配合CSRF攻击五、Medium级别passed_captcha的“虚假安全感”5.1 安全级别设置将DVWA Security切换为Medium级别。5.2 观察变化在Medium级别下尝试Low级别的方法直接添加step2发现被阻止了。5.3 源码分析查看Medium级别的核心代码?php if( isset( $_POST[ Change ] ) ( $_POST[ step ] 1 ) ) { // Hide the CAPTCHA form $hide_form true; // Get input $pass_new $_POST[ password_new ]; $pass_conf $_POST[ password_conf ]; // Check CAPTCHA from 3rd party $resp recaptcha_check_answer( $_DVWA[ recaptcha_private_key ], $_POST[g-recaptcha-response] ); // Did the CAPTCHA fail? if( !$resp ) { // What happens when the CAPTCHA was entered incorrectly $html . prebr /The CAPTCHA was incorrect. Please try again./pre; $hide_form false; return; } else { // CAPTCHA was correct. Do both new passwords match? if( $pass_new $pass_conf ) { // Show next stage for the user echo prebr /You passed the CAPTCHA! Click the button to confirm your changes.br //pre form action\#\ method\POST\ input type\hidden\ name\step\ value\2\ / input type\hidden\ name\password_new\ value\{$pass_new}\ / input type\hidden\ name\password_conf\ value\{$pass_conf}\ / input type\hidden\ name\passed_captcha\ value\true\ / input type\submit\ name\Change\ value\Change\ / /form; } else { // Both new passwords do not match. $html . preBoth passwords must match./pre; $hide_form false; } } } if( isset( $_POST[ Change ] ) ( $_POST[ step ] 2 ) ) { // Hide the CAPTCHA form $hide_form true; // Get input $pass_new $_POST[ password_new ]; $pass_conf $_POST[ password_conf ]; // Check to see if they did stage 1 if( !$_POST[ passed_captcha ] ) { $html . prebr /You have not passed the CAPTCHA./pre; $hide_form false; return; } // Check to see if both password match if( $pass_new $pass_conf ) { // They do! $pass_new ((isset($GLOBALS[___mysqli_ston]) is_object($GLOBALS[___mysqli_ston])) ? mysqli_real_escape_string($GLOBALS[___mysqli_ston], $pass_new ) : ((trigger_error([MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work., E_USER_ERROR)) ? : )); $pass_new md5( $pass_new ); // Update database $insert UPDATE users SET password $pass_new WHERE user . dvwaCurrentUser() . ;; $result mysqli_query($GLOBALS[___mysqli_ston], $insert ) or die( pre . ((is_object($GLOBALS[___mysqli_ston])) ? mysqli_error($GLOBALS[___mysqli_ston]) : (($___mysqli_res mysqli_connect_error()) ? $___mysqli_res : false)) . /pre ); // Feedback for the end user echo prePassword Changed./pre; } else { // Issue with the passwords matching echo prePasswords did not match./pre; $hide_form false; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } ?Medium级别的变化增加了passed_captcha参数第一步验证通过后服务器生成一个包含passed_captchatrue的表单第二步检查passed_captcha只有passed_captchatrue时才执行密码修改本质上仍然是客户端可控passed_captcha参数由客户端提交5.4passed_captcha的局限性Medium级别的改进看起来比Low级别更安全但本质上没有任何区别问题说明参数仍由客户端控制passed_captcha是POST参数攻击者可以随意添加没有服务端状态记录服务器没有在Session中记录“已验证”状态可被直接伪造攻击者只需添加passed_captchatrue即可绕过5.5 攻击方法伪造passed_captcha参数攻击步骤第一步正常填写表单输入新密码和确认密码点击提交。第二步使用Burp Suite抓包拦截到请求。第三步修改参数将请求修改为关键点step2直接跳到第二步passed_captchatrue告诉服务器“我已经通过验证码了”第四步放行请求页面显示“Password Changed”密码修改成功。5.6 Medium级别总结改进局限性增加了passed_captcha检查参数仍由客户端控制第二步有验证逻辑验证的是客户端提交的参数有一定防护效果本质上与Low级别无异六、High级别后门与User-Agent的“诡异组合”6.1 安全级别设置将DVWA Security切换为High级别。6.2 观察变化在High级别下尝试Medium级别的方法添加step2和passed_captchatrue发现被阻止了。6.3 源码分析查看High级别的核心代码?php if( isset( $_POST[ Change ] ) ) { // Hide the CAPTCHA form $hide_form true; // Get input $pass_new $_POST[ password_new ]; $pass_conf $_POST[ password_conf ]; // Check CAPTCHA from 3rd party $resp recaptcha_check_answer( $_DVWA[ recaptcha_private_key ], $_POST[g-recaptcha-response] ); if ( $resp || ( $_POST[ g-recaptcha-response ] hidd3n_valu3 $_SERVER[ HTTP_USER_AGENT ] reCAPTCHA ) ){ // CAPTCHA was correct. Do both new passwords match? if ($pass_new $pass_conf) { $pass_new ((isset($GLOBALS[___mysqli_ston]) is_object($GLOBALS[___mysqli_ston])) ? mysqli_real_escape_string($GLOBALS[___mysqli_ston], $pass_new ) : ((trigger_error([MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work., E_USER_ERROR)) ? : )); $pass_new md5( $pass_new ); // Update database $insert UPDATE users SET password $pass_new WHERE user . dvwaCurrentUser() . LIMIT 1;; $result mysqli_query($GLOBALS[___mysqli_ston], $insert ) or die( pre . ((is_object($GLOBALS[___mysqli_ston])) ? mysqli_error($GLOBALS[___mysqli_ston]) : (($___mysqli_res mysqli_connect_error()) ? $___mysqli_res : false)) . /pre ); // Feedback for user echo prePassword Changed./pre; } else { // Ops. Password mismatch $html . preBoth passwords must match./pre; $hide_form false; } } else { // What happens when the CAPTCHA was entered incorrectly $html . prebr /The CAPTCHA was incorrect. Please try again./pre; $hide_form false; return; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?High级别的变化增加了g-recaptcha-response检查要求该参数等于hidd3n_valu3增加了User-Agent检查要求User-Agent等于reCAPTCHA这是设计者故意留下的后门backdoor6.4 后门机制的原理High级别的代码中服务器检查g-recaptcha-response参数是否等于hidd3n_valu3User-Agent头是否等于reCAPTCHA这两个值都是硬编码的而且完全由客户端控制。这意味着攻击者只需要在请求中添加g-recaptcha-responsehidd3n_valu3并将User-Agent修改为reCAPTCHA即可绕过验证码验证6.5 攻击方法伪造后门参数攻击步骤第一步正常填写表单输入新密码和确认密码点击提交。第二步使用Burp Suite抓包拦截到请求。第三步修改请求关键修改添加step2参数添加g-recaptcha-responsehidd3n_valu3参数将User-Agent修改为reCAPTCHA第四步放行请求页面显示“Password Changed”密码修改成功。6.6 High级别总结防御机制作用绕过方法g-recaptcha-response检查要求特定值添加hidd3n_valu3User-Agent检查要求特定UA修改为reCAPTCHA硬编码后门设计者故意留下知道后门值即可绕过七、Impossible级别终极防御方案7.1 安全级别设置将DVWA Security切换为Impossible级别。7.2 界面观察进入Impossible级别的页面你会发现多了一个输入框——Current password当前密码。现在修改密码需要输入三个字段Current password当前密码New password新密码Confirm new password确认新密码7.3 源码分析查看Impossible级别的核心代码?php if( isset( $_POST[ Change ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ user_token ], $_SESSION[ session_token ], index.php ); // Hide the CAPTCHA form $hide_form true; // Get input $pass_new $_POST[ password_new ]; $pass_new stripslashes( $pass_new ); $pass_new ((isset($GLOBALS[___mysqli_ston]) is_object($GLOBALS[___mysqli_ston])) ? mysqli_real_escape_string($GLOBALS[___mysqli_ston], $pass_new ) : ((trigger_error([MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work., E_USER_ERROR)) ? : )); $pass_new md5( $pass_new ); $pass_conf $_POST[ password_conf ]; $pass_conf stripslashes( $pass_conf ); $pass_conf ((isset($GLOBALS[___mysqli_ston]) is_object($GLOBALS[___mysqli_ston])) ? mysqli_real_escape_string($GLOBALS[___mysqli_ston], $pass_conf ) : ((trigger_error([MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work., E_USER_ERROR)) ? : )); $pass_conf md5( $pass_conf ); $pass_curr $_POST[ password_current ]; $pass_curr stripslashes( $pass_curr ); $pass_curr ((isset($GLOBALS[___mysqli_ston]) is_object($GLOBALS[___mysqli_ston])) ? mysqli_real_escape_string($GLOBALS[___mysqli_ston], $pass_curr ) : ((trigger_error([MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work., E_USER_ERROR)) ? : )); $pass_curr md5( $pass_curr ); // Check CAPTCHA from 3rd party $resp recaptcha_check_answer( $_DVWA[ recaptcha_private_key ], $_POST[g-recaptcha-response] ); // Did the CAPTCHA fail? if( !$resp ) { // What happens when the CAPTCHA was entered incorrectly echo prebr /The CAPTCHA was incorrect. Please try again./pre; $hide_form false; } else { // Check that the current password is correct $data $db-prepare( SELECT password FROM users WHERE user (:user) AND password (:password) LIMIT 1; ); $data-bindParam( :user, dvwaCurrentUser(), PDO::PARAM_STR ); $data-bindParam( :password, $pass_curr, PDO::PARAM_STR ); $data-execute(); // Do both new password match and was the current password correct? if( ( $pass_new $pass_conf) ( $data-rowCount() 1 ) ) { // Update the database $data $db-prepare( UPDATE users SET password (:password) WHERE user (:user); ); $data-bindParam( :password, $pass_new, PDO::PARAM_STR ); $data-bindParam( :user, dvwaCurrentUser(), PDO::PARAM_STR ); $data-execute(); // Feedback for the end user - success! echo prePassword Changed./pre; } else { // Feedback for the end user - failed! echo preEither your current password is incorrect or the new passwords did not match.br /Please try again./pre; $hide_form false; } } } // Generate Anti-CSRF token generateSessionToken(); ?7.4 Impossible级别的五重防御体系Impossible级别构建了五重防御体系彻底杜绝了验证码绕过的可能性第一层CSRF Token验证使用checkToken()函数验证请求中的user_token是否与会话中的session_token一致防止跨站请求伪造攻击。第二层验证码验证合并到主流程最关键的变化验证码验证不再是一个独立的步骤而是与密码修改合并到同一个请求中。之前的设计步骤1验证码→ 步骤2改密码 之后的设计一步完成验证码 改密码同时验证攻击者无法再通过跳过步骤来绕过验证码。第三层当前密码验证核心防御用户修改密码时必须输入当前密码。攻击者即使绕过了验证码也不知道用户的当前密码无法完成密码修改。第四层PDO预处理防SQL注入使用PDO预处理语句执行数据库查询彻底杜绝了SQL注入的可能性防止攻击者通过SQL注入获取当前密码。第五层一次性Token刷新每次请求后调用generateSessionToken()生成新的Token每个Token只能使用一次。7.5 为什么Impossible级别无法被绕过要成功攻击Impossible级别攻击者需要同时满足以下条件条件Impossible级别的防护攻击者能否达成绕过CSRF TokenToken验证❌ 无法伪造有效Token绕过验证码验证码与改密合并为一步❌ 无法跳过绕过当前密码验证必须输入当前密码❌ 不知道密码通过SQL注入获取密码PDO预处理❌ 无法注入重放Token一次性Token刷新❌ Token已失效五重防护叠加使得Insecure CAPTCHA攻击在Impossible级别下完全不可行。7.6 Impossible级别总结防御层技术手段作用第一层CSRF Token验证防止跨站请求伪造第二层验证码与改密合并消除步骤跳过漏洞第三层当前密码验证即使绕过验证码也无法改密第四层PDO预处理防止SQL注入窃取密码第五层一次性Token防止请求重放八、防御Insecure CAPTCHA的最佳实践通过DVWA四个级别的对比我们可以总结出防御验证码绕过漏洞的最佳实践8.1 必须实施的防御措施措施说明优先级验证码与操作合并不要将验证码验证和核心操作分为两个步骤⭐⭐⭐⭐⭐服务端状态记录在Session中记录验证状态不依赖客户端参数⭐⭐⭐⭐⭐当前密码验证修改密码等关键操作要求输入当前密码⭐⭐⭐⭐⭐CSRF Token使用Anti-CSRF Token防止跨站请求伪造⭐⭐⭐⭐⭐服务端验证所有验证逻辑必须在服务端完成不依赖前端⭐⭐⭐⭐⭐8.2 推荐的辅助措施措施说明优先级验证码有效期验证码应有有效期限制过期失效⭐⭐⭐⭐验证码一次性每个验证码只能使用一次⭐⭐⭐⭐绑定会话验证码与用户会话绑定⭐⭐⭐⭐操作日志记录所有敏感操作便于审计⭐⭐⭐8.3 常见误区在实际开发中以下做法不能有效防御验证码绕过❌将验证码验证分为两步攻击者可以直接跳到第二步❌使用客户端提交的布尔值判断如passed_captchatrue❌硬编码后门值如High级别的hidd3n_valu3❌仅依赖前端验证攻击者可以绕过前端直接发请求❌验证码与操作分离没有原子性保证九、总结本文围绕不安全验证码漏洞展开系统学习我们先了解验证码是区分人机、抵御自动化攻击的图灵测试明确不安全验证码漏洞根源为验证流程逻辑割裂、程序过度信任客户端可控参数由此存在绕过风险我们逐级完成 DVWA 各安全等级实操Low 级别直接篡改 step 请求参数跳过验证码校验步骤Medium 依靠客户端 passed_captcha 标记判断验证状态该参数可直接伪造实现绕过High 预留特殊后门构造指定 g-recaptcha-response 参数与 User-Agent 请求头即可绕过验证码Impossible 整合 CSRF Token、验证码与改密操作绑定、原密码校验、PDO 预处理、一次性验证码令牌五层防护彻底消除绕过隐患同时总结出验证码与业务操作绑定、服务端存储校验状态、关键操作原密码验证、搭配 CSRF Token 等安全防护方案。不安全验证码漏洞的核心隐患是验证逻辑分离、过度信任客户端数据借助 DVWA 的 Insecure CAPTCHA 模块我们同步掌握各类验证码绕过攻击手法与防护逻辑在真实生产环境中将验证码与核心操作绑定、服务端独立管理验证状态并增加原密码二次校验多重防护结合能够从根本上避免验证码被恶意绕过。重要声明本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。如果这篇文章帮你解决了实操上的困惑别忘记点击点赞、分享也可以留言告诉我你遇到的其它问题我会尽快回复。你的关注是我坚持原创和细节共享的力量来源谢谢大家。

相关新闻

足球口袋教练 HarmonyOS 离线应用实战(16/20):用户画像、身体指标与风险提示

足球口袋教练 HarmonyOS 离线应用实战(16/20):用户画像、身体指标与风险提示

本文是“足球口袋教练 HarmonyOS 离线应用实战”系列第 16 篇。示例项目是一个 HarmonyOS / ArkTS / ArkUI 编写的离线足球训练助手 本篇要解决的问题 个人资料页不能只是昵称头像。对训练工具来说,用户画像应该影响计划生成、风险提示和训练负荷,否则画…

2026/7/4 4:03:19阅读更多 →
足球口袋教练 HarmonyOS 离线应用实战(14/20):AVSession 与后台音频任务

足球口袋教练 HarmonyOS 离线应用实战(14/20):AVSession 与后台音频任务

本文是“足球口袋教练 HarmonyOS 离线应用实战”系列第 14 篇。示例项目是一个 HarmonyOS / ArkTS / ArkUI 编写的离线足球训练助手 本篇要解决的问题 语音提示一旦进入后台,就不只是 TTS 问题,还会涉及系统播放状态、后台任务和播控卡片。如果状态没写…

2026/7/4 4:03:19阅读更多 →
Tkinter库的学习记录18-Treeview

Tkinter库的学习记录18-Treeview

18、Treeview Treeview是tkinter.ttk的控件,这个控件主要是提供多栏的显示功能,我们可以称其为树状表格数据(Treeview)。在设计时也可以在左边栏设计成树状结构或是称层次结构,用户可以显示或隐藏任何部分,这个最左边的栏称为图标…

2026/7/4 4:03:19阅读更多 →
Arduino编程入门:基于LittleArduinoProjects的快速学习路径

Arduino编程入门:基于LittleArduinoProjects的快速学习路径

Arduino编程入门:基于LittleArduinoProjects的快速学习路径 【免费下载链接】LittleArduinoProjects a collection of "Little Electronic & Arduino Projects", most involving electronics or an Arduino in one way or another! 项目地址: https…

2026/7/4 8:03:44阅读更多 →
终极视频AI放大神器:Video2X完全指南,让老旧视频重获4K新生

终极视频AI放大神器:Video2X完全指南,让老旧视频重获4K新生

终极视频AI放大神器:Video2X完全指南,让老旧视频重获4K新生 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_T…

2026/7/4 8:03:44阅读更多 →
PyMiniRacer终极入门:从安装到执行第一条JS代码的完整教程

PyMiniRacer终极入门:从安装到执行第一条JS代码的完整教程

PyMiniRacer终极入门:从安装到执行第一条JS代码的完整教程 【免费下载链接】PyMiniRacer PyMiniRacer is a V8 bridge in Python. 项目地址: https://gitcode.com/gh_mirrors/py/PyMiniRacer PyMiniRacer是一个Python中的V8桥接工具,它让开发者能…

2026/7/4 8:03:43阅读更多 →
Heya高级功能解析:如何利用用户分段实现精准邮件营销

Heya高级功能解析:如何利用用户分段实现精准邮件营销

Heya高级功能解析:如何利用用户分段实现精准邮件营销 【免费下载链接】heya Heya 👋 is a campaign mailer for Rails. Think of it like ActionMailer, but for timed email sequences. It can also perform other actions like sending a text message…

2026/7/4 8:03:43阅读更多 →
NCSN核心原理揭秘:为什么估计数据分布梯度能革新生成建模?

NCSN核心原理揭秘:为什么估计数据分布梯度能革新生成建模?

NCSN核心原理揭秘:为什么估计数据分布梯度能革新生成建模? 【免费下载链接】ncsn Noise Conditional Score Networks (NeurIPS 2019, Oral) 项目地址: https://gitcode.com/gh_mirrors/nc/ncsn Noise Conditional Score Networks(NCSN…

2026/7/4 8:03:43阅读更多 →
Instatic与CMS趋势:现代静态网站生成与管理的终极指南

Instatic与CMS趋势:现代静态网站生成与管理的终极指南

Instatic与CMS趋势:现代静态网站生成与管理的终极指南 【免费下载链接】Instatic Instatic is a modern self-hosted visual CMS - get it running in 1 minute 项目地址: https://gitcode.com/GitHub_Trending/in/Instatic 在当今快速发展的Web开发领域&…

2026/7/4 7:58:43阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/3 14:18:39阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/3 14:38:35阅读更多 →
端到端自动驾驶:从GTC‘26看工程可信落地的核心逻辑

端到端自动驾驶:从GTC‘26看工程可信落地的核心逻辑

1. 项目概述:当算法工程师走进GTC26展厅,看到的不是芯片,而是“端到端”的呼吸节奏“端到端”这三个字,在GTC’26现场出现的频率,高得像NVLink带宽测试时的峰值曲线——它不再是一个论文里的技术路径选项,而…

2026/7/4 0:02:48阅读更多 →
缺牙修复科普:常见义齿类型与选择参考

缺牙修复科普:常见义齿类型与选择参考

缺牙修复科普:常见义齿类型与选择参考牙齿缺失是中老年人群中较为常见的口腔问题,不仅会造成咀嚼不便、进食受影响,长期还可能对营养摄入与日常社交带来困扰。义齿是改善缺牙问题的常用方式,目前市面上的义齿种类较多,…

2026/7/4 0:02:48阅读更多 →
STM32F091RC与LTC6904实现高精度方波信号生成

STM32F091RC与LTC6904实现高精度方波信号生成

1. 项目概述:LTC6904与STM32F091RC的精准方波生成方案在嵌入式系统开发中,精确的时钟信号和定时控制往往是项目成败的关键。LTC6904作为一款低功耗、高精度的可编程振荡器芯片,与STM32F091RC这款ARM Cortex-M0内核微控制器的组合,…

2026/7/4 0:02:48阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/4 1:16:56阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/4 2:33:55阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/4 2:33:55阅读更多 →