在 Web 安全中,服务端一直扮演着十分重要的角色。然而前端的问题也不容小觑,它也会导致信息泄露等诸如此类的问题。在这篇文章中,我们将向读者介绍如何防范Web前端中的各种漏洞。【万字长文,请先收藏再阅读】

首先,我们需要了解安全防御产品已经为我们做了哪些工作。其次,我们将探讨前端存在哪些漏洞,并提供相应的防范思路。

一、安全防御产品

安全防御产品一般有:

传统互联网公司的安全防御体系,类似于一个空气净化模型,每个层都有不同的产品,包括网络层防护、应用层防护、主机层防护、运行时防护、安全开发防护和安全运营防护。外部攻击流量经过过滤后,到达应用系统的流量相对较为安全。

对于我们前端而言,最有用的是安全开发防护层中的白盒和黑盒。白盒扫描是对我们的源代码进行扫描,在上线时会自动检测问题。黑盒扫描则不考虑程序的结构和代码细节,对应用程序进行漏洞扫描,每天都有定时任务扫描公网。

在安全方面,我们与集团安全部门进行双向合作。在集团安全防御体系已经做了一些工作的基础上,我们如何针对前端可能存在的漏洞进行防范,是我们研发部门需要思考的问题。

二、漏洞防范

1、安全传输

首先,务必使用HTTPS协议,这可以有效防止局域网内的明文抓包。

2、域分离

其次,进行域分离。将一些业务关联性较小的内容转移到不相关的域中。如果分离域下出现了XSS漏洞,不会影响业务主域,而且分离域下的XSS漏洞也无法获得奖励。如果所有内容都在主域下,一旦主域出现漏洞,主域下的所有子域都会受到破坏。

前端领域常见的漏洞有3种XSS漏洞、CSRF漏洞、界面操作劫持漏洞

3、XSS防御方案

对于概念,包括名词定义、攻击方式、解决方案等估计大家都看过不少,但留下印象总是很模糊,要动手操作一番才能加深印象并能真正理解。

1)XSS 模拟攻击

先动手实现一个 XSS 的攻击场景,然后再讲解 XSS 的防范手段。看这个代码:

点击“write”按钮后,会在页面插入一个a链接,a链接的跳转地址是文本框的内容。在这里,通过innerHTML把一段用户输入的数据当做HTML写入到页面中,这就造成了XSS漏洞。尝试如下输入:

首先用一个单引号闭合掉href的第一个单引号,然后闭合掉标签,然后插入一个img标签。页面代码变成了:

脚本被执行:

所以你明白了吧,XSS跨站脚本攻击就是注入一段脚本,并且该脚本能够被执行。其中最常见的XSS Payload就是读取浏览器的Cookie对象。通过盗取Cookie,攻击者可以直接调用接口,发起“Cookie劫持”攻击。

为了防止“Cookie劫持”,集团的统一登录使用了Cookie的“HttpOnly”和“Secure”标识。

HttpOnly标识表示该Cookie仅在HTTP层面传输。一旦设置了HttpOnly标志,客户端脚本就无法读写该Cookie,从而有效地防御XSS攻击获取Cookie的风险。

Secure标识确保Cookie只在加密的HTTPS连接中传输,从而降低了“Cookie劫持”的风险。

因此,建议避免使用localStorage存储敏感信息,哪怕这些信息进行过加密。因为localStorage存储,没有针对XSS攻击,做任何防御机制。一旦出现XSS漏洞,那么存储在localStorage里的数据就极易被获取到。

2)XSS的危害

让我们简单谈谈XSS的危害。注入的脚本可能会进行JavaScript函数劫持,覆盖我们代码中原有的函数,修改js原型链上的函数,或在原函数基础上添加额外行为。例如,将网络请求的响应发送到攻击者的服务器。

JavaScript函数劫持是什么?它是在目标函数触发之前重写某个函数的过程。例如:

let _write = document.write.bind(document);
document.write = function(x) {
if(typeof(x) == "undefined") { return; }
_write(x);
}

注入的脚本还可能对用户进行内存攻击。如果知道用户使用的浏览器、操作系统,攻击者就有可以实施一次精准的浏览器内存攻击。通过XSS,可以读取浏览器的UserAgent对象。

alert(navigator.userAgent);

该对象提供了客户端的信息,如操作系统版本:Mac OS X 10_15_7,浏览器版本:Chrome/114.0.0.0

注入的脚本可能强制弹出广告页面、刷流量,也可能进行大量的DDoS攻击,导致网络拥塞。此外,它还可能控制受害者的机器向其他网站发起攻击。

如果信贷产品的网页存在XSS漏洞,黑客可以注入一段脚本,调用查询借还记录的接口,并将响应结果发送到自己的服务器。然后,利用用户的借还记录等信息,对用户进行电信诈骗。

第三方统计脚本有机会窃取用户的敏感信息,如浏览历史、真实IP、地理位置、设备信息,并将其传送给攻击者。此外,我们使用的第三方依赖和npm包也有可能窃取用户信息。在这方面,集团对代码进行了白盒扫描,已一定程度上规避问题。但最好我们在选择第三方包时,选择可信赖的包。

3)XSS 防范方法

XSS 防范方法通常有以下几种:

①慎防第三方内容:对于流行的统计脚本和第三方依赖,要谨慎使用。

②输入校验和输出编码:进行输入校验,包括长度限制、值类型是否正确以及是否包含特殊字符(如<>)。同时,在输出时进行相应的编码,根据输出的位置选择适当的编码方式,如HTML编码和URL编码。

③使用HttpOnly属性:防范XSS攻击后的"cookie劫持"。

使用Secure属性,确保Cookie只在加密的HTTPS连接中传输,降低"cookie劫持"的风险。

④避免使用localStorage存储敏感信息。

⑤使用Content-Security-Policy(内容安全策略):可以通过指定只允许加载来自特定域名的脚本,防范XSS攻击,例如,可以使用以下配置只允许加载来自mjt.jd.com域名的脚本

# 只允许加载来自特定域名的脚本
add_header Content-Security-Policy "script-src mjt.jd.com";

4、CSRF防御方案

CSRF漏洞是借用用户的权限做一些事情,注意,是“借用”,而不是“盗取”。XSS漏洞是“盗取”用户权限,CSRF漏洞是“借用”用户权限。

1)CSRF 模拟攻击

我们先动手实现一个 CSRF 攻击场景,然后再介绍 CSRF 的防范手段。我们要模拟以下场景:用户先登录了银行网站,然后黑客网站诱导用户访问和点击,从而利用用户的登录权限,让用户给黑客自己转账。我们使用 express 启动一个服务,模拟 CSRF 攻击。银行网站的服务启动在 3001 端口,并提供以下3个接口:

app.use('/', indexRouter);
app.use('/auth', authRouter);
app.use('/transfer', transferRouter);

authRouter:

router.get('/', function(req, res, next) {
res.cookie('userId', 'ce032b305a9bc1ce0b0dd2a', { expires: new Date(Date.now() + 900000) })
res.end('ok')
});

/auth 接口在 cookie 中设置了一个名为 userId 的 cookie,即给用户授予登录权限。

transferRouter:

router.get('/', function(req, res, next) {
const { query } = req;
const { userId } = req.cookies;
if(userId){
res.send({
status: 'transfer success',
transfer: query.number
})
}else{
res.send({
status: 'error',
transfer: ''
})
}
});

/transfer 接口判断了 cookie,如果存在 cookie,则转账成功,否则转账失败。

使用 ejs 提供银行转账页面:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
<%= title %>
</title>
</head> <body>
<h2>
转账
</h2>
<script>
const h2 = document.querySelector('h2');
h2.addEventListener('click', () => {
fetch('/transfer?number=15000&to=Bob').then(res => {
console.log(res.json());
})
})
</script>
</body> </html>

黑客网站的服务启动在 3002 端口,并提供一个与银行网站外观相同的页面:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
</head> <body> <div class="wrapper" id="container">
<h2>
转账
</h2>
<form action="http://bank.com/transfer" method=GET>
<input type="hidden" name="number" value="150000" />
<input type="hidden" name="to" value="Jack" />
</form>
<script>
const h2 = document.querySelector('h2');
h2.addEventListener('click', () => {
submitForm();
})
function submitForm() {
document.forms[0].submit();
}
</script>
</div>
</body>
</html>

由于两个网站都是在 localhost 域名下,cookie 是根据域名而不是端口进行区分的。因此,我们使用 Whistle 进行域名映射:

# bank.com 映射到 127.0.0.1:3001
bank.com 127.0.0.1:3001 # hack.com 映射到 127.0.0.1:3002
hack.com 127.0.0.1:3002

现在我们开始操作。首先打开浏览器,访问银行网站 的 /auth获得授权:

然后通过点击”转账”按钮发送请求,http://bank.com/transfer?number=15000&to=Bob,进行转账操作:

用户受到邮件或者广告诱惑进入了 黑客网站,黑客网站首页有一个“转账”按钮,调银行的transfer接口 http://bank.com/transfer?number=150000&to=Jack 这个请求放在

的 action 中

可以看到请求携带了 cookie,并成功转账,这样一次 CSRF 攻击就完成了。

从上面可以看出,CSRF 攻击的主要特点是:

①发生在第三方域名(hack.com)

②攻击者利用 cookie 而不获取具体的 cookie 值

因此,防范 CSRF 攻击的关键是防止其他人冒充你去执行只有你能执行的敏感操作。

2)CSRF 危害

简单说,CSRF会导致:个人隐私泄露、机密资料泄露、甚至危及用户和企业的财产安全。一句话概括CSRF的危害:盗用受害者身份,受害者能做什么,攻击者就能以受害者的身份做什么。

3)CSRF 防范方法

①阻止不同域的访问:同源检测

在HTTP请求中检查Referer或origin字段,确保请求来源是站内地址和站内域名。如果发现Referer或origin地址异常,就可以怀疑遭到了CSRF攻击。

②使用验证码

尽管会降低用户体验,但验证码是防止CSRF攻击的最有效手段。

③提交时要求附加本域才能获取的信息

例如使用一次性token(生成token的因子包括时间戳和用户ID)来验证请求的合法性。

④不要允许所有域访问,使用allow-access-from domain时避免以下方式,即根据前端请求的域来允许访问:

        String origin = request.getHeader("origin");
if (StringUtils.isNotEmpty(origin)) {
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
} else {
response.setHeader("Access-Control-Allow-Origin", "*");
}

这种方式是不可取的,应该限制访问的域。

5、界面操作劫持防御方案

它是一种基于视觉欺骗的攻击方式,其核心在于利用标签的透明属性。攻击者会在网页的可见输入控件上覆盖一个不可见的框,从而让用户误以为自己在操作可见控件,实际上却是在操作不可见框。

界面操作劫持还包括:点击劫持、拖放劫持、触屏劫持

1)常见的攻击场景

点击劫持的常见攻击场景是伪造登录框。当用户在伪造的登录框中输入用户名和密码后,他们以为自己点击的是登录页面上的登录按钮,但实际上他们点击的是黑客页面上的“登录”按钮,导致密码被发送到黑客的服务器上。

拖放劫持利用了拖放操作不受“同源策略”限制的特点,用户可以把一个域的内容拖放到另一个不同的域。攻击者结合CSRF漏洞,将iframe中目标网页的token拖放到攻击者的页面中,从而实施攻击。

触屏劫持是在手机上进行的一种视觉欺骗攻击。由于手机屏幕空间有限,手机浏览器会隐藏地址栏以节省空间。攻击者常常利用这一点,当触发一个权限获取的提示框时,他们会将提示框的主体背景设为透明,并覆盖上伪造的消息提示图像,只留下权限提示框的确认按钮。这样,用户会误以为自己在点击某个消息的确认,实际上却是在点击权限确认。

2)界面操作劫持的防范方法

①Content-Security-Policy (内容安全策略)

# 防御界面操作劫持
# add_header Content-Security-Policy "frame-ancestors 'self';"; # 只允许网页在相同被嵌套到框架
# add_header Content-Security-Policy "frame-ancestors 'none';"; # 禁止网页在任何域名下被嵌套到框架
# add_header Content-Security-Policy "frame-ancestors mkt.shop.jd.com"; # 只允许网页在某些域名被嵌套到框架

②脚本防御:破坏frame,防止利用透明层进行操作劫持攻击

    if (top === self) {
document.documentElement.style.display = 'block';
} else {
top.location = self.location;
}

③使用iframe嵌入目标网站进行测试,若成功嵌入,则说明可能存在漏洞。

三、培养安全意识

为了确保代码的安全性,我们需要培养以下几点安全意识:

通过培养这些安全意识,我们可以更好地保护我们的代码和系统,减少安全风险和潜在的攻击。

作者:京东科技 张朝阳

来源:京东云开发者社区

聚焦Web前端安全:最新揭秘漏洞防御方法的更多相关文章

  1. 十分钟看懂,未来Web前端开发最新趋势

    首先,展望未来趋势我们就要弄懂过去的一年,也就是18年,web前端开发的重要新闻.重要事件和JavaScript的各种流行框架.模式发展趋势. 我们来快速回顾一下. NPM热门前端框架下载 先来看最热 ...

  2. Web前端--黑客技术揭秘(菜鸟知识)

    一,Web安全的关键点 1.同源策略是众多安全策略的一个,是Web层面上的策略.很重要. 2.同源策略规定:不同域的client脚本在没明白授权的情况下.不能读写对方的资源. 3.同域要求两个网站同协 ...

  3. [在读]web前端黑客技术揭秘

  4. web前端教程之javascript创建对象的方法

    今天给大家讲讲javascript基础教程中的javascript面向对象的技术,这一次我们深入的学习一下JavaScrip基于t面向对象之创建对象,关于面向对象的一些术语这里就不给大家介绍了,不了解 ...

  5. web前端面试第一次[javascript函数和方法的区别]

    //函数 function f1(){ console.log("我是函数"); } //调用函数 f1(); //创建一个空对象 var obj = {} //把函数定义到对象里 ...

  6. WEB前端 [编码] 规则浅析

    前言 说到前端安全问题,首先想到的无疑是XSS(Cross Site Scripting,即跨站脚本),其主要发生在目标网站中目标用户的浏览器层面上,当用户浏览器渲染整个HTML文档的过程中出现了不被 ...

  7. Web前端性能优化——如何有效提升静态文件的加载速度

    WeTest 导读 此文总结了笔者在Web静态资源方面的一些优化经验. 一.如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标.那么为了提高页 ...

  8. web前端性能优化,提升静态文件的加载速度

    原文地址:传送门 WeTest 导读 此文总结了笔者在Web静态资源方面的一些优化经验. 如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标. ...

  9. web前端安全---读书笔记

    web前端安全---读书笔记 粗略的看完了Web前端黑客技术揭秘前两章了,由于自身的前端功力不深,当然也是初涉前端的安全问题,所以实话还是有些问题看不太明白的.在豆瓣看到的这本书,名字真心有点很肥主流 ...

  10. 整理六百篇web前端知识混总

    9个有用的和免费的工具来支持动态网页开发 8个基本的引导工具的网页设计师 11款CSS3动画工具的开发 2016年某前端群题目答案参考 9最好的JavaScript压缩工具 创建响应式布局的10款优秀 ...

随机推荐

  1. 2022-07-30:以下go语言代码输出什么?A:[]byte{} []byte;B:[]byte{} []uint8;C:[]uint8{} []byte;D:[]uin8{} []uint8。

    2022-07-30:以下go语言代码输出什么?A:[]byte{} []byte:B:[]byte{} []uint8:C:[]uint8{} []byte:D:[]uin8{} []uint8. ...

  2. 2022-04-01:有n个人,m个任务,任务之间有依赖记录在int[][] depends里。 比如: depends[i] = [a, b],表示a任务依赖b任务的完成, 其中 0 <= a <

    2022-04-01:有n个人,m个任务,任务之间有依赖记录在int[][] depends里. 比如: depends[i] = [a, b],表示a任务依赖b任务的完成, 其中 0 <= a ...

  3. status能否设置为布尔值类型,前端采用复选框形式

    是的,可以将status设置为布尔类型,这样可以在前端使用复选框形式展示.在模型中的定义可以如下: class Acceptance(models.Model): # ... status = mod ...

  4. Django4全栈进阶之路10 url路由设置

    在 Django 4 中,可以在主路由文件中设置和管理子路由.通常,我们会为每个应用程序创建一个子路由文件,以便更好地组织代码和管理路由. 以下是 Django 4 中设置主路由和子路由的示例: 首先 ...

  5. 【Java】JTable的数据刷新

    前言 这段时间在写一个大实验,水果超市管理系统,yes,我觉得挺大的,但是就当成了一个实验,接下来还有一个课程设计和一个实训,more bigger... 问题 在我把其他的都写好的时候去写UI层,发 ...

  6. MyBatis 在大数据量下使用流式查询进行数据同步

    通常的数据同步中,如果数据量比较少的话可以直接全量同步,默认情况下,完整的检索结果集会将其存储在内存中.在大多数情况下,这是最有效的操作方式,并且由于 MySQL 网络协议的设计,因此更易于实现.但是 ...

  7. Windows常用的 CMD 命令合集

    常用的 CMD 命令合集: 基础命令 dir:列出当前目录中的文件和子目录. cd:更改当前目录.例如,cd Documents 将当前目录更改为 Documents 文件夹. md 或 mkdir: ...

  8. 深入解析React DnD拖拽原理,轻松掌握拖放技巧!

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值.. 本文作者:霁明 一.背景 1.业务背景 业务中会有一些需要实现拖拽 ...

  9. Hive执行计划之什么是hiveSQL向量化模式及优化详解

    Hive开启向量化模式也是hiveSQL优化方法中的一种,可以提升hive查询速率,也叫hive矢量化. 问题1:那么什么是hive向量化模式呢? 问题2:hive向量化什么情况下可以被使用,或者说它 ...

  10. 一分钟学一个 Linux 命令 - find 和 grep

    前言 大家好,我是 god23bin.欢迎来到<一分钟学一个 Linux 命令>系列,每天只需一分钟,记住一个 Linux 命令不成问题.今天需要你花两分钟时间来学习下,因为今天要介绍的是 ...