前端安全防护措施避坑指南|零基础掌握XSS/CSRF防护+数据加密实用技巧

前端安全防护措施避坑指南|零基础掌握XSS/CSRF防护+数据加密实用技巧 一

文章目录CloseOpen

从原理到实操:XSS和CSRF防护的落地方法

很多人觉得前端安全是后端的事,其实前端才是第一道防线。就像你家大门,后端是防盗门,前端就是门口的门禁——如果门禁没关好,陌生人随便就能按门铃捣乱。我见过不少项目,后端用了顶级的安全框架,前端却连最基础的输入验证都没做,结果照样被攻击。下面我就拆解开XSS和CSRF这两个“老熟人”,用你能听懂的话讲清楚怎么防。

XSS防护:别让网页成了“恶意代码展示板”

XSS(跨站脚本攻击)说白了就是坏人往你的网页里塞恶意代码,用户打开页面时代码执行,就能偷cookie、弹广告,甚至控制用户账号。我刚开始做前端时,以为“输入框限制长度”就叫防护,结果在一个博客项目里栽了跟头——有用户在评论区输入alert(document.cookie),提交后所有访问该页面的用户都弹框显示自己的cookie,当时我脸都白了。

常见的XSS攻击有三种,你可以记这个简单分类

攻击类型 简单理解 常见场景
存储型XSS 恶意代码存到数据库,所有人可见 评论区、用户资料页
反射型XSS 代码通过URL参数传到页面,只攻击当前用户 搜索结果页、错误提示页
DOM型XSS 代码不经过后端,直接通过JS操作DOM执行 用location.hash、localStorage渲染页面

知道了原理,防护就简单了。我 了三个“必做动作”,哪怕只做前两个,也能挡住80%的XSS攻击:

第一步:输入验证——给用户的输入“画红线”

。你可以理解为给输入框装个“安检仪”,不符合规则的直接拦在门外。比如评论区只允许文字和表情,就把script这些危险字符过滤掉。我现在做项目都会用validator.js这个库(非广告,纯粹自己觉得好用),它能帮你快速配置规则,比如只允许字母、数字和中文,代码大概长这样:

// 简单的输入验证示例

function validateComment(input) {

const reg = /^[u4e00-u9fa5a-zA-Z0-9,.,。!!??;;、s]+$/;

return reg.test(input);

}

不过要注意,别只靠前端验证,后端必须再做一遍——毕竟懂技术的人能绕过前端验证直接发请求。

第二步:输出编码——让恶意代码“说胡话”

。就算输入验证漏了网,输出到页面时给代码“变个声”,浏览器就认不出它是恶意代码了。比如把<变成<>变成>,这样就会显示成普通文本,不会执行。我之前踩坑后,现在写Vue项目必用v-text代替v-html(除非万不得已用v-html,那就必须先编码),React项目就用textContent代替innerHTML,这些都是框架自带的安全机制,不用白不用。 第三步:CSP策略——给网页“设防火墙”。这个稍微进阶一点,但设置好能防很多高级攻击。CSP(内容安全策略)就像给网页立了个规矩:只允许加载指定域名的资源,不准执行内联脚本。你可以在服务器配置里加个响应头Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com,意思是只允许加载自己域名和可信CDN的脚本。OWASP(开放Web应用安全项目)的XSS防护指南里特别推荐这个方法,你可以去看看他们的详细文档(https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.htmlnofollow),写得很详细。

CSRF防护:别让用户在“不知情”下发请求

说完XSS,再聊聊CSRF(跨站请求伪造),这个比XSS更“阴险”——它不偷你信息,而是冒用你的身份干坏事。举个例子:你刚在银行网站登录,没退出就打开了一个恶意网页,这个网页里藏着一段“转账到坏人账户”的代码,因为你还登录着银行网站,浏览器会自动带上你的cookie,银行一看有cookie,就以为是你发的请求,钱就转走了。

我自己的博客后台就差点出这个问题。之前做“删除文章”功能时,直接用了GET请求,参数是文章ID,结果有次测试,同事用我的账号打开他做的一个页面,里面放了个前端安全防护措施避坑指南|零基础掌握XSS/CSRF防护+数据加密实用技巧 二,我那篇写了一周的教程就这么被删了!后来查了才知道是CSRF攻击,赶紧改成POST请求,还加了Token验证。

防护CSRF,这三个方法你至少要做一个:

方法一:加个“验证码”——让用户“证明是自己”

。最直接的就是转账、改密码这类关键操作,必须输入验证码或短信验证。但这个影响用户体验,不能所有操作都加,适合重要场景。 方法二:Token验证——给请求“发通行证”。这是我现在最常用的方法,简单说就是:服务器给每个用户生成一个随机的Token,存在session里,前端请求时必须带上这个Token,服务器验证Token对不对,才处理请求。比如你登录后,后端返回csrfToken: "a1b2c3...",前端发请求时就在header里加X-CSRF-Token: a1b2c3...。我用Axios的话,会全局配置拦截器自动加Token,省得每个请求都写一遍:

// Axios拦截器自动加CSRF Token

axios.interceptors.request.use(config => {

config.headers['X-CSRF-Token'] = localStorage.getItem('csrfToken');

return config;

});

方法三:SameSite Cookie——给Cookie“设门禁”

。这个是浏览器自带的功能,给Cookie加个SameSite属性,告诉浏览器:这个Cookie只能在自己网站用,别的网站发请求时别带。你可以在后端设置Cookie时加上SameSite=Strict(完全禁止跨站带Cookie)或SameSite=Lax(部分允许),现在主流浏览器都支持这个属性,配置起来也简单,Nginx或Apache里加一行就行。

数据加密:前端敏感信息“藏好”的实用技巧

除了防攻击,前端还有个大事:怎么保护用户的敏感信息?比如手机号、银行卡号、登录密码这些,总不能直接明文传输或存储吧?我之前帮一个医疗项目做前端,他们一开始把患者身份证号直接存在localStorage里,被安全审计批了一顿——万一用户电脑中毒,这些信息不就全泄露了?后来我们改成加密存储,才通过审核。下面这两个场景你肯定会碰到,我把具体怎么做告诉你。

场景一:传输加密——让数据“穿隐身衣”

数据从前端发到后端的路上,最容易被“偷听”。你可能觉得“我用了HTTPS啊,还需要加密吗?”HTTPS确实能加密传输,但万一HTTPS证书出问题(比如被中间人攻击),或者后端接口有漏洞,数据还是可能泄露。所以敏感信息最好在前端先“包一层”。

我常用的是AES加密,它就像给数据加个密码锁,只有知道密钥的人才能打开。具体怎么做呢?你可以用crypto-js这个库(同样非广告,社区常用),先在前端用AES加密敏感数据,后端用同样的密钥解密。比如用户登录时,密码不直接发,而是加密后发:

// AES加密示例(密钥存在后端,前端通过安全接口获取)

import CryptoJS from 'crypto-js';

// 假设从后端安全接口获取密钥

const secretKey = '从后端请求的随机密钥';

function encryptPassword(password) {

return CryptoJS.AES.encrypt(password, secretKey).toString();

}

// 登录时发加密后的密码

axios.post('/login', {

username: 'user123',

password: encryptPassword('userPassword123')

});

这里有个关键:密钥不能存在前端!之前见过有人把密钥写死在代码里,那等于没加密——懂行的人一看源码就知道密钥了。正确做法是:用户登录时,后端先返回一个临时密钥(比如用RSA加密传给前端),前端用这个密钥加密数据,用完就销毁,这样才安全。

场景二:本地存储——别让localStorage成“保险柜”

很多人图方便,把用户信息、token直接存在localStorage或sessionStorage里,觉得“反正用户自己的电脑,没事”。但你想想:如果用户用的是公用电脑,或者浏览器被植入了恶意插件,这些信息不就被偷走了?我之前做的一个项目,就是把用户的收货地址存在localStorage,结果有用户反馈地址被篡改,查了才发现是他电脑里的恶意插件读取了localStorage数据。

所以本地存敏感信息,一定要加密。我一般这么做:

  • 用sessionStorage代替localStorage:sessionStorage关闭浏览器就清空,比localStorage安全点,适合存临时数据。
  • 加密存储:非要存在localStorage,就用AES加密后再存,密钥可以存在内存里(比如一个全局变量),用户关闭页面就没了。代码大概这样:
  • // 加密存储敏感信息
    

    function saveSensitiveData(key, data) {

    const encrypted = CryptoJS.AES.encrypt(JSON.stringify(data), memoryKey).toString();

    localStorage.setItem(key, encrypted);

    }

    // 读取时解密

    function getSensitiveData(key) {

    const encrypted = localStorage.getItem(key);

    if (!encrypted) return null;

    const bytes = CryptoJS.AES.decrypt(encrypted, memoryKey);

    return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));

    }

  • 少存敏感信息:能不存本地就不存,比如用户手机号,需要时从后端接口拿,用完就删掉,别长期存在前端。
  • 对了,MDN的Web Crypto API文档里有更详细的加密方法(https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Crypto_APInofollow),如果你想了解底层原理,可以去看看,写得很权威。

    其实前端安全没那么玄乎,就像居家防盗——门(输入验证)、窗(输出编码)、保险柜(加密)都做好,坏人就很难进来。我自己这些方法都是踩坑踩出来的,刚开始也觉得复杂,后来发现只要把基础的几招练熟,80%的安全问题都能解决。你可以先从XSS的输入验证和CSRF的Token验证做起,这两个最容易上手,做完再逐步完善加密和CSP策略。

    如果你按这些方法试了,或者之前在安全防护上踩过别的坑,欢迎在评论区告诉我效果,咱们一起把前端安全这道防线筑得更牢!


    说实话,前端安全这事儿真不是前端一个人能扛起来的,就像你开家小店,前端是门口的保安,负责拦住明显的可疑人员,后端才是店里的保险柜,管着最核心的东西——保安再厉害,保险柜没锁好,照样白搭。我见过太多项目,前端把输入验证、输出编码做得滴水不漏,结果后端接口直接把用户输入的内容存进数据库,连个特殊字符过滤都没有,最后用户一打开页面,存储型XSS攻击直接弹框,之前前端做的防护全成了摆设。

    你可能觉得“我前端都把这种标签过滤掉了,还能有什么问题?”但懂行的人根本不用通过你前端的输入框——他们可以直接用Postman发请求,把恶意代码直接传到后端。我去年帮一个电商平台改安全问题时就碰到过这种情况:前端评论区明明限制了只能输入文字,结果有个攻击者用API工具直接提交了带XSS代码的评论,后端没做二次过滤,直接存进了数据库,导致所有访问商品详情页的用户都中招。后来我们前后端一起改:前端加强了输入格式校验,后端增加了HTML特殊字符过滤和输出编码,才算彻底堵上这个窟窿。所以你看,前端是“第一道岗”,后端是“最后一道闸”,少了哪道都不行,必须前后端“手拉手”才能把安全做到位。


    前端安全防护只靠前端就够了吗?

    不是的,前端安全需要前后端配合,就像你家的安全需要门禁和防盗门一起作用。前端负责第一道过滤(比如输入验证、输出编码),但后端必须做最终防护(比如接口验证、数据过滤),因为懂技术的人可能绕过前端直接发请求。我之前见过前端防护做得很好,但后端没过滤特殊字符,照样被存储型XSS攻击,所以前后端“双保险”才靠谱。

    怎么快速检测项目里有没有XSS漏洞?

    推荐两个简单方法,零基础也能上手。一是手动测试:在输入框里试试输入alert(1),提交后看页面会不会弹窗——如果弹窗就说明有漏洞。二是用浏览器插件,比如“XSS Detector”,它能自动扫描页面里的可疑脚本。 开发时用Vue的话,可以检查有没有滥用v-html,React项目看看有没有用innerHTML,这些都是常见漏洞点。

    本地存储加密后就绝对安全了吗?

    不是绝对安全,但能大大降低风险。加密能防住普通恶意插件或公用电脑的信息泄露,但如果攻击者能获取到你的加密密钥(比如通过内存读取),还是可能解密。所以除了加密,你还要注意:敏感数据尽量用sessionStorage(关闭页面就清空),密钥别存在localStorage或代码里,用完就从内存删除,多重防护比单一加密更可靠。

    用了框架自带的安全机制(如Vue的v-text),还需要手动做输入验证吗?

    需要!框架自带的安全机制(比如Vue的v-text会自动编码)能防大部分DOM型XSS,但输入验证是“第一道关”。举个例子:如果用户输入攻击代码,v-text会显示成文本,但如果这段内容要存到数据库(比如评论),没做输入验证的话,后端返回给其他用户时还是可能触发存储型XSS。所以框架机制+手动验证,双重防护更稳妥。

    前端数据加密的密钥怎么安全管理?

    密钥管理的核心是“别让密钥存在前端”。我常用的方法是:用户登录后,后端通过HTTPS返回一个临时密钥(比如用RSA加密传给前端),前端用这个密钥加密数据,用完就从内存删除(比如页面关闭或登出时清空)。千万别把密钥写死在代码里或存在localStorage——之前有项目这么做,结果密钥被人从源码里找到,加密等于白做。

    0
    显示验证码
    没有账号?注册  忘记密码?