白帽视角:开发人员如何避免常见 Web 安全漏洞

发布时间:2026/10/14 3:41:06
白帽视角:开发人员如何避免常见 Web 安全漏洞
法律免责声明本文站在白帽安全测试视角面向研发人员讲解 Web 漏洞成因、错误代码案例与安全编码修复方案仅用于企业内部安全开发学习请勿用于未授权渗透攻击。所有漏洞案例均为模拟业务代码不指向任何真实线上业务系统。目录1. 开发人员必须建立的基础安全思维1.1 永远不要信任任何外部输入1.2 白名单优于黑名单1.3 最小权限原则1.4 失败安全原则Secure‑by‑Fail2. 注入类漏洞防护SQL 注入命令注入表达式注入2.1 SQL 注入2.2 命令注入2.3 SSTI 模板注入3. XSS 跨站脚本漏洞前端后端联合防御3.1 危险场景3.2 CSP 内容安全策略深度防御3.3 开发常见误区4. 文件相关漏洞文件上传、文件包含、目录遍历4.1 文件上传漏洞4.2 目录遍历路径穿越4.3 文件包含漏洞5. 访问控制类漏洞垂直越权、水平越权、未授权访问6. CSRF、CORS 跨域配置错误防护方案6.1 CSRF 跨站请求伪造6.2 CORS 跨域配置错误7. 业务逻辑漏洞验证码、密码重置、重复提交7.1 验证码相关漏洞高频坑7.2 密码重置漏洞7.3 业务重复提交、逻辑绕过8. 反序列化、XXE 高危漏洞开发避坑8.1 Java 反序列化8.2 XXE XML 外部实体注入9. 开发高频踩坑清单那些自以为安全的错误写法10. 框架层面安全最佳实践SpringBoot / PHP10.1 SpringBoot 开发安全要点10.2 PHP 开发安全要点11. 软件研发流程中如何嵌入安全左移安全12. 上线前自查安全 Checklist直接复制使用输入校验文件功能权限访问控制业务逻辑Web 头与 Cookie其他13. 写在最后安全不是附加功能是业务的一部分最后关于网络安全技术储备对于0基础小白入门摘要大量线上 Web 安全漏洞并非全部来自复杂的 0day 漏洞绝大多数高危漏洞来源于开发阶段编码不规范、安全意识缺失、只重视功能忽略安全逻辑。很多开发同学会认为安全是安全测试、WAF、运维的事情实际上漏洞根源产生在代码编写阶段。本文从白帽挖洞实战视角梳理线上高频出现的 Web 安全漏洞SQL 注入、XSS 跨站脚本、命令注入、文件上传、越权访问、CSRF、业务逻辑漏洞、反序列化、CORS 配置错误、文件包含等对比危险代码与安全修复代码分析开发过程常见安全误区给出可直接落地的编码规范、安全检查清单、开发流程安全实践。帮助后端、前端、全栈开发者在写业务代码时从源头规避安全风险减少 SRC 上报、漏洞扫描爆出高危漏洞降低数据泄露、被入侵 getshell 的业务风险。前言在 SRC 漏洞平台大量的上报漏洞中70% 以上的高危漏洞属于 “开发可完全避免” 的问题。白帽子拿到一个系统不需要多么高深的技术仅仅修改请求参数、构造特殊字符、篡改前端数据就可以触发高危漏洞。为什么会出现这种现象开发的核心目标是实现业务功能安全经常被后置很多开发者依赖前端校验认为前端拦掉后端就不会收到恶意数据网上复制粘贴 Demo 代码没有甄别 Demo 代码是否存在安全缺陷框架提供安全能力但人为绕开框架安全机制手动拼接 SQL、拼接命令业务逻辑漏洞没有工具扫描单元测试不会覆盖安全场景上线直接暴露将安全防护全部寄托于 WAFWAF 可以被绕过代码层才是最后防线。WAF、扫描器属于外部防护手段真正的安全防线在业务代码内部。如果代码本身存在漏洞无论上层防护多强都存在被绕过的可能性。本文不只是讲漏洞原理更多站在开发者视角告诉你写代码的时候哪些坑不能踩遇到对应业务场景应该怎么写安全代码。1. 开发人员必须建立的基础安全思维在写每一行业务代码前先建立 4 条核心安全思维几乎所有 Web 漏洞都违背下面几条原则。1.1 永远不要信任任何外部输入一切来自 HTTP 请求的数据都是不可信的GET 参数、POST 表单、JSON Body、Cookie、Header 请求头、上传文件内容、URL 路径参数。攻击者完全可以绕过前端页面使用 Burp、脚本构造任意恶意请求。前端校验只能做用户体验优化不能作为安全防护手段。很多开发做了 JS 校验文件后缀就认为上传是安全的攻击者抓包直接修改数据包防护完全失效。所有校验逻辑必须在服务端二次实现。1.2 白名单优于黑名单黑名单禁止某些危险字符白名单只允许合法内容。黑名单永远防不全攻击者有编码、变形、大小写、注释等无数绕过方式。尽可能优先使用白名单校验定义 “什么是合法”非法输入直接拒绝而不是过滤掉 “什么是非法”。举例子文件上传不要写 “禁止 php 后缀”应该写 “只允许 jpg/png/gif”。1.3 最小权限原则应用账号、数据库账号、服务器运行账号只分配完成业务必须的最小权限即使被攻击者利用漏洞也尽可能缩小危害范围。Web 服务运行账号不要用 root、administrator业务数据库账号不允许访问 mysql 系统库不允许 FILE 写文件权限普通业务接口禁止读取服务器本地敏感文件。1.4 失败安全原则Secure‑by‑Fail权限校验、参数校验逻辑如果程序发生异常、报错默认拒绝访问而不是默认放行。错误示范权限判断发生异常直接跳过校验执行业务逻辑正确示范校验逻辑异常直接返回 403 拒绝访问。2. 注入类漏洞防护SQL 注入命令注入表达式注入注入类漏洞是 OWASP Top10 常年高危类型成因把外部可控输入直接拼接进 SQL 语句、系统命令、代码表达式攻击者篡改原有逻辑。2.1 SQL 注入危险代码示例Java错误写法字符串拼接 SQL// 高危直接拼接用户传入name参数 String name request.getParameter(name); String sql select * from user where username name ; stmt.executeQuery(sql);攻击者传入 or 11直接拖库。✅安全修复使用预编译参数化查询PreparedStatementString sql select * from user where username ?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1,name); ResultSet rs pstmt.executeQuery();PHP 危险写法// 危险字符串拼接 $sql select * from user where username .$_GET[user].;PHP 安全写法 PDO 预编译$stmt $pdo-prepare(select * from user where username :username); $stmt-bindParam(:username,$_GET[user]); $stmt-execute();重要避坑点很多开发使用 Mybatis仍然手写({}字符串拼接造成注入#{}预编译\){}直接字符串拼接禁止业务参数使用${}。!-- 高危 -- select * from user where username ${username} !-- ✅安全 -- select * from user where username #{username}特殊场景排序、表名无法预编译此时不能直接接收前端参数需要做白名单枚举校验不允许直接传入原始参数。// 排序字段白名单校验 String sortBy request.getParameter(sort); ListString allowSort Arrays.asList(id,create_time,name); if(!allowSort.contains(sortBy)){ return 非法参数; }2.2 命令注入业务中有时候需要调用系统命令比如 ping 网络检测。如果把用户输入直接拼接到系统 shell 命令出现命令注入漏洞。危险 Java 代码// 高危用户可控ip直接拼接命令 String ip request.getParameter(ip); Runtime.getRuntime().exec(ping -c 4 ip);攻击者传入127.0.0.1;cat /etc/passwd执行任意系统命令。✅安全方案尽可能避免直接调用系统命令优先使用 SDK、内部函数实现业务不要调用 shell无法避免调用命令时严格白名单校验输入禁止特殊符号; | $ 使用数组形式 exec避免 shell 解析元字符。Java 安全示例String ip request.getParameter(ip); //简单IP格式校验 if(!ip.matches(^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$)){ return IP格式非法; } //数组传入不经过shell解析 String[] cmd {ping,-c,4,ip}; Runtime.getRuntime().exec(cmd);2.3 SSTI 模板注入不要把用户输入直接传入模板引擎渲染Freemarker、Thymeleaf、Twig 如果渲染可控用户数据会造成 SSTI执行服务器代码。业务场景邮件模板、自定义页面功能极易踩坑。禁止templateEngine.process(userInput,context)用户输入不能作为模板源码。3. XSS 跨站脚本漏洞前端后端联合防御XSS 分为反射型、存储型、DOM‑XSS成因可控用户输入未经处理输出到 HTML 页面浏览器将用户输入当做 JS 代码执行。很多开发以为只需要前端转义实际上存储型 XSS 需要后端输出编码。3.1 危险场景留言板用户提交❌危险后端伪代码//直接把用户评论输出到HTML页面 out.print(divcomment/div);✅安全方案输出编码根据输出上下文选择转义方式输出到 HTML 正文HTML 实体编码 ’ 转义输出到 JS 变量JS 转义输出到 CSSCSS 转义输出到标签属性属性编码。SpringBoot 开发可以使用 OWASP‑Java‑Encoder 工具包做上下文编码。//html正文输出编码 String safeComment Encoder.forHtml(comment); out.print(divsafeComment/div);前端 DOM‑XSS 重点禁止直接使用innerHTML、outerHTML、document.write、eval()处理外部可控数据优先使用textContent自动转义。3.2 CSP 内容安全策略深度防御配置 HTTP 响应头 Content‑Security‑Policy即使出现 XSS也阻止脚本执行属于深度防御手段不能替代编码修复。示例响应头Content‑Security‑Policy: default‑src self; script‑src self3.3 开发常见误区误区 1后端过滤掉script标签就安全。攻击者可以用img onloadalert(1)、svg onloadalert(1)绕过黑名单过滤。黑名单过滤 XSS 不可靠优先输出编码。误区 2前端框架Vue/React就不会 XSS。框架插值{{ }}自动编码但 v‑html、dangerouslySetInnerHTML 会关闭转义可控数据传入就会触发 XSS。4. 文件相关漏洞文件上传、文件包含、目录遍历文件类漏洞是高危漏洞重灾区很多业务都有头像上传、附件下载功能稍有不注意直接 getshell。4.1 文件上传漏洞❌高危开发错误只做前端 JS 校验只校验 MIME‑Type只修改文件名但保留原始后缀上传目录允许脚本解析。完整安全上传步骤缺一不可服务端二次校验不要依赖前端 JS 校验文件后缀采用白名单仅允许业务需要的后缀如 jpg、png校验文件真实文件头不仅仅看文件名后缀后端重新生成随机文件名丢弃用户原始文件名防止 00 截断、双后缀攻击上传文件存储目录关闭脚本解析权限上传目录不要直接可以执行 php/jsp文件存放在 web 访问目录之外通过接口读取返回返回下载的时候设置响应头X‑Content‑Type‑Options: nosniff、Content‑Disposition:attachment浏览器直接下载不解析执行。危险示例用户上传shell.php.jpg后端没有校验文件内容web 服务器存在解析漏洞执行脚本。4.2 目录遍历路径穿越业务场景文件下载url 传入 filename 参数读取服务器文件。危险/download?filename../etc/passwd❌危险伪代码String filename request.getParameter(filename); File file new File(./upload/filename);攻击者使用../跳出业务目录读取服务器任意敏感文件。✅修复方案对文件名做路径标准化禁止../白名单数据库存储文件 ID不要直接传入文件名参数根据 ID 查询真实文件路径强制限定基础目录。File baseDir new File(./upload); File targetFile new File(baseDir,filename); //判断文件是否在基础目录内防止跳出 if(!targetFile.getCanonicalPath().startsWith(baseDir.getCanonicalPath())){ return 非法访问; }4.3 文件包含漏洞PHP include、require 直接引入外部用户可控参数。//高危 include($_GET[page]);✅修复禁止直接包含用户输入白名单限定可包含的文件名称。5. 访问控制类漏洞垂直越权、水平越权、未授权访问越权漏洞属于业务逻辑漏洞扫描器很难发现但是在 SRC 上报数量非常高很多开发很容易忽略。水平越权同角色A 用户可以查看 / 修改 B 用户数据。普通用户 A 修改请求里 user_id2直接访问用户 2 订单信息。垂直越权低权限普通用户访问管理员接口执行管理员操作。未授权访问没有登录校验直接访问后台管理接口。❌典型错误逻辑接口接收前端传过来的orderId直接查询数据库没有校验当前登录用户是否属于这条订单的拥有者。//高危只根据orderId查询没有和当前登录用户绑定 Order order orderMapper.selectById(orderId);✅正确逻辑每一个涉及用户私有资源的接口拿到资源 ID 之后必须结合当前登录会话中的 userId 做权限校验不要信任前端传入的用户标识必须从 session/token 会话里面获取真实登录身份。//当前登录用户从session/token获取不是前端传参 Long loginUserId (Long)session.getAttribute(userId); Order order orderMapper.selectById(orderId); if(order null || !order.getUserId().equals(loginUserId)){ return Result.fail(无权访问); }未授权访问常见坑后台接口忘记添加登录拦截器静态资源、controller 接口忽略鉴权注解。SpringSecurity 开发注意不要写PermitAll放开不该公开的接口。开发自测越权小技巧登录 A 账号拿到订单 ID复制 ID打开 B 账号手动传入这个 ID 调用接口看是否可以访问成功。6. CSRF、CORS 跨域配置错误防护方案6.1 CSRF 跨站请求伪造原理用户登录网站后访问恶意网站恶意网站自动发起请求利用浏览器 Cookie 自动携带执行业务操作。高危场景修改密码、绑定手机号、支付、重要业务提交接口。✅防御手段状态改变接口增加 CSRF‑Token服务端校验 tokentoken 不能放在 Cookie需要放在请求体 /headerCookie 设置 SameSite 属性SameSiteStrict/Lax重要操作增加验证码、二次确认。SpringSecurity 默认开启 CSRF 防护不要随意关闭 csrf ().disable ()。误区仅仅校验 Referer。Referer 可以被攻击者伪造不能作为唯一防护。6.2 CORS 跨域配置错误很多开发为了解决前后端跨域直接配置允许全部来源Access‑Control‑Allow‑Origin: *或者获取请求 Origin 直接回写没有校验造成 CORS 漏洞攻击者恶意域名可以读取接口返回的用户敏感数据。❌高危错误 Java 伪代码//高危直接把请求Origin返回 response.setHeader(Access‑Control‑Allow‑Origin,request.getHeader(Origin));✅安全配置允许的域名配置固定白名单列表判断 Origin 是否在白名单再设置响应头不要同时配置*和Allow‑Credentials:true标准不允许线上环境禁止允许任意 Origin。ListString allowOriginList Arrays.asList(https://a.com,https://b.com); String origin request.getHeader(Origin); if(allowOriginList.contains(origin)){ response.setHeader(Access‑Control‑Allow‑Origin,origin); response.setHeader(Access‑Control‑Allow‑Credentials,true); }7. 业务逻辑漏洞验证码、密码重置、重复提交业务逻辑漏洞没有标准 Payload完全是业务设计缺陷扫描器很难检测但是 SRC 上报占比极高。7.1 验证码相关漏洞高频坑验证码客户端校验后端不校验前端删掉验证码参数直接提交成功验证码复用不销毁同一个验证码可以无限次使用验证码弱4 位纯数字无频率限制可以暴力爆破返回包直接返回验证码密码重置验证码绑定手机号但是修改请求中的手机号用 A 收到的验证码修改 B 账号密码。✅安全编码规范验证码生成存储在服务端 session/redis提交时后端校验校验通过立即销毁验证码限制同一个手机号获取验证码频率限制验证码有效期验证码校验时必须绑定对应的账号不能只校验验证码本身。7.2 密码重置漏洞常见缺陷重置链接的参数使用用户 id没有随机 token攻击者遍历 id 批量重置账号重置 token 长期有效。✅修复生成高熵随机 uuid token 存入数据库设置过期时间不要使用自增 id 作为重置凭证。7.3 业务重复提交、逻辑绕过比如低价购买商品、优惠券重复领取前端限制后端没有幂等校验攻击者重复发包多次领取优惠券。✅修复后端增加幂等、事务锁数据库唯一约束不能只依靠前端按钮置灰。开发测试逻辑漏洞思路修改 http 请求每一个参数观察业务逻辑会不会发生预期之外变化。8. 反序列化、XXE 高危漏洞开发避坑8.1 Java 反序列化不要反序列化不可信的外部输入数据。ObjectInputStream.readObject()直接解析 http 传来的数据会触发反序列化 RCE。禁止直接反序列化外部可控数据如果业务需要序列化传输使用 JSON 替代原生 Java 序列化开启序列化白名单校验。8.2 XXE XML 外部实体注入解析 XML 文档如果开启外部实体攻击者构造 XML 读取服务器本地文件。Java 中 SAX、DocumentBuilder 解析 XML默认部分版本开启外部实体。✅修复解析 XML 时关闭 DTD、外部实体解析。SpringBoot 中如果接收 XML 请求注意配置关闭外部实体业务尽量优先使用 JSON减少 XML 解析。PHP libxml 处理 XML禁止加载外部实体。9. 开发高频踩坑清单那些自以为安全的错误写法很多漏洞并不是完全不懂安全而是一些想当然的错误认知整理开发高频踩坑点。❌“前端已经校验过后端不用校验” →所有输入后端必须二次校验前端只是体验优化❌“加了 WAF代码漏洞没关系” → WAF 可以被编码、变形绕过代码层才是根本修复❌“黑名单过滤危险字符就安全” → 黑名单永远绕不完优先白名单校验❌Mybatis 使用({}接收业务参数以为框架可以防注入 →\){}直接字符串拼接会产生注入❌文件上传只校验后缀名不校验文件内容上传目录允许脚本解析❌越权接口直接使用前端传入 user_id、order_id不结合登录会话身份校验❌CORS 跨域直接把 Origin 请求头原样返回不做域名白名单❌验证码校验完成不销毁支持重复使用❌日志打印用户密码、token 等敏感信息造成日志泄露❌接口错误堆栈直接返回给前端泄露服务器路径、类名、版本信息生产环境关闭详细异常栈统一返回业务错误码。❌Cookie 不设置 HttpOnlyXSS 盗取 Cookie重要 Cookie 配置 HttpOnly、Secure 属性。❌把密钥、数据库密码硬编码写在代码里面上传 git密钥泄露。密钥放到环境变量、配置中心禁止提交到版本仓库。10. 框架层面安全最佳实践SpringBoot / PHP10.1 SpringBoot 开发安全要点优先使用 SpringSecurity不要手写登录鉴权不要随意关闭 csrf鉴权注解不要遗漏controller 方法粒度控制权限不要依赖前端隐藏按钮使用 JSR‑303 参数校验Valid后端做参数校验长度、格式、非空生产关闭 banner关闭详细异常堆栈输出统一全局异常处理器添加安全响应头X‑Frame‑Options、X‑Content‑Type‑Options、Content‑Security‑Policy依赖组件定期升级避免 log4j2、fastjson 等组件漏洞定期扫描第三方依赖漏洞。10.2 PHP 开发安全要点禁止使用原始 mysql_query使用 PDO 预编译php.ini 关闭危险函数disable_functionsexec、system、passthru 等不需要的系统函数关闭错误回显 display_errorsOff生产环境不要输出 PHP 报错文件上传目录禁止 php 脚本执行权限不要使用 $_REQUEST 接收全部参数明确 GET/POST 来源。框架不等于自动安全框架提供防护但是开发者人为绕过框架能力手动拼接 SQL、拼接命令依旧会产生高危漏洞。11. 软件研发流程中如何嵌入安全左移安全安全不应该等到测试、上线之后再发现修复要 “安全左移”在需求、开发阶段就考虑安全。需求阶段涉及登录、密码重置、上传、支付、权限管理的需求同步思考安全风险点开发编码阶段开发人员掌握基础安全编码规范复制网上 Demo 代码确认 Demo 是否存在安全漏洞代码评审环节安全敏感接口增加安全评审点重点看SQL 拼接、文件上传、权限校验、外部输入处理测试阶段不仅仅测试功能是否正常补充安全测试用例越权、验证码、注入、上传上线前依赖漏洞扫描使用 SAST 静态代码扫描工具扫描代码上线后定期更新组件版本关注漏洞通告收到 SRC 漏洞反馈及时修复更新。很多公司把安全全部交给安全团队但业务代码量巨大安全团队无法全部覆盖每一个开发人员才是安全第一道防线。12. 上线前自查安全 Checklist直接复制使用开发完成上线前对照清单快速自查接口安全输入校验所有 HTTP 输入后端全部校验不依赖前端校验SQL 全部使用预编译禁止直接字符串拼接排序表名做白名单系统命令调用尽量避免必须调用做严格白名单过滤文件功能文件上传后缀白名单重新生成随机文件名校验文件内容上传目录关闭脚本执行文件下载防止路径穿越不直接接收文件名参数权限访问控制所有私有资源接口做身份鉴权从会话获取登录用户不相信前端传入用户 ID测试水平、垂直越权切换账号修改资源 ID 访问接口后台接口没有忘记鉴权、没有 PermitAll 误放开业务逻辑验证码后端校验校验完成销毁绑定账号有过期时间防暴力密码重置使用随机 Token不使用自增 ID重复操作接口增加幂等、锁处理Web 头与 CookieCORS 配置域名白名单不直接回写 Origin敏感 Cookie 设置 HttpOnly、Secure添加基础安全响应头关闭 X‑Powered‑By 版本泄露生产环境不输出详细异常堆栈其他密钥密码不硬编码在代码不提交 git第三方依赖组件版本定期更新排查高危组件漏洞13. 写在最后安全不是附加功能是业务的一部分很多开发同学觉得安全是额外的负担优先保证功能跑通安全以后再说。但线上一旦出现高危漏洞会带来用户数据泄露、业务被入侵、合规处罚、品牌受损修复漏洞的成本远高于开发阶段规避漏洞的成本。从白帽挖洞视角看大部分高危漏洞都不是高深的 0day都是简单的编码疏忽没有做后端校验、直接拼接 SQL、没有做越权判断、上传没有严格限制。攻击者利用这些简单缺陷就可以造成巨大的业务损失。安全不是安全工程师一个团队的事情而是每一个研发人员的责任。掌握基础安全编码思维写代码的时候多思考一句这个参数来自外部攻击者篡改这个参数会发生什么问题WAF、安全设备属于 “防御盾牌”而健壮安全的业务代码才是根基。希望本文可以帮助开发同学理解攻击者视角在编码阶段规避绝大多数 Web 高危漏洞。最后关于网络安全技术储备学好网络安全不论是就业还是做副业赚钱都不错但要学会网络安全还是要有一个学习规划。最后大家分享一份全套的网络安全学习资料给那些想学习网络安全的小伙伴们一点帮助对于0基础小白入门如果你是零基础小白想快速入门网络安全是可以考虑的。一方面是学习时间相对较短学习内容更全面更集中。二方面是可以找到适合自己的学习方案包括网安成长学习路线图、SRC黑客文档、护网行动、黑客必读书单、面试题、学习视频等教程。带你从零基础系统性的学好网络安全需要的可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】1.成长路线图学习规划要学习一门新的技术作为新手一定要先学习成长路线图方向不对努力白费。对于从来没有接触过网络安全的同学我们帮你准备了详细的学习成长路线图学习规划。可以说是最科学最系统的学习路线大家跟着这个大的方向学习准没问题。2.网安入门到进阶视频教程很多朋友都不喜欢晦涩的文字我也为大家准备了视频教程其中一共有21个章节每个章节都是当前板块的精华浓缩。全套教程文末领取哈3.SRC黑客文档大家最喜欢也是最关心的SRC技术文籍黑客技术也有收录SRC技术文籍黑客资料由于是敏感资源这里不能直接展示哦全套教程文末领取哈4.护网行动资料其中关于HW护网行动也准备了对应的资料这些内容可相当于比赛的金手指5.黑客必读书单随着互联网技术的飞速发展网络安全已经成为了当今科技领域的一大热点。这些SQL注入、CCNA、Web渗透、Linux服务器等以其强大的语言理解和防御能力正在守护着我们网络世界。 那以下这些PDF籍就是非常不错的学习资源。6.网络安全岗面试题合集当你自学到这里你就要开始思考找工作的事情了而工作绕不开的就是真题和面试题。这份完整版的网络安全学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】