你应该知道的前端安全性

本文不是一个大而全的课程,只是咱们平常中常见的问题,由于网络安全是一个很大的话题,咱们这里只介绍前端工程师应知应会的东西。大概包括 XSS, CSRF, 点击劫持,SQL注入,OS注入,请求劫持,DDOS,以及简单的防范策略。javascript

1.XSS

XSS的英文是Cross Site Scripting也就是常说的跨站脚本***,由于缩写和CSS重叠,因此只能叫XSS,跨站脚本***是指经过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或JavaScript进行的一种***。html

那么XSS通常是如何进行***的呢?假设咱们页面中存在一个input或者textarea用来收集用户输入的数据,正常状况下不会有什么问题,假设用户输入的内容为 <script>alert(1)</script>。当咱们将用户输入的这段内容经过innnerHTML添加到页面中时,就会运行该段代码,弹出alert。前端

document.body.innerHTML = inputValue;复制代码

能够发现,用户输入的js脚本是能够被执行的,这样的话就造成了一个安全漏洞,不少***都是先经过alert的方式先去试验网站是否能够被XSS,这也就意味着能够运行js里面的任何脚本。用户在不知情的状况下输入的帐号密码会被***记录发送给本身,也能够经过js改写页面显示非法图片,将用户的登陆状态复制到***的电脑上***可使用用户的身份进行操做等等。vue

通常XSS的***方式有两种,一种是上面介绍的经过input输入的方式进行***叫作存储型,就是用户输入的内容会存储到数据库,每次打开页面都会执行,另外一种是经过url参数***叫作反射型,假设咱们网站url中携带的内容会渲染到页面。java

http://localhost:8080/index.html?name=yd复制代码

***能够发送以下的连接给用户,用户一旦打开就会执行脚本。mysql

http://localhost:8080/index.html?name=<script>alert(123)</script>复制代码

XSS的危害有哪些,简单来讲javascript能作什么,他就能够作什么。react

1.获取页面数据jquery

2.获取Cookiesgit

3.修改前端逻辑程序员

4.发送请求

5.获取用户的信息和登陆态

6.欺骗用户

如何防止XSS***呢?

  1. 能够在header中设置响应头 X-XSS-Protection,默认状况下禁止XSS***的,若是检测到url中存在XSS***,页面是拒绝访问的。可是他对存储型的***是无效的,只能拦截url中存在注入***的状况。
ctx.set('X-XSS-Protection', 0); // 容许XSS***复制代码

值有以下4种:

  • 0 容许XSS***

  • 1 禁止XSS***。若是检测到跨站脚本***,浏览器将清除页面(删除不安全的部分)

  • 1;mode=block 启用XSS过滤,若是检测到***,浏览器将不会清除页面,而是阻止页面加载。

  • 1report= 启用XSS过滤,若是检测到跨站脚本***,浏览器将清除页面并使用CSP report-uri 指令的功能发送违规报告。

一般状况下浏览器会默认设置为1,禁止XSS***。

  1. CSP

内容安全策略(CSP Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的***,包括XSS和数据注入等***。这些***可用于实现从数据窃取到网站破坏或做为恶意软件分发版本等用途。

CSP本质上就是创建白名单,开发者明确告诉浏览器哪些外部资源能够加载和执行,咱们只须要配置规则,如何拦截是浏览器本身实现的,咱们能够经过这种方式来尽可能减小XSS***。

这个策略他有以下几种方式:

// 只容许加载本站资源Content-Security-Policy: default-src 'self'// 只容许加载HTTPS协议图片Content-Security-Policy: img-src https://*// 不容许加载任何来源框架Content-Security-Policy: child-src 'none'复制代码

通常被***是咱们的网站执行了其余网站的js脚本,注入了***的js代码。假设咱们的网站设置了只容许加载本身网站的代码,那么注入的js脚本就没办法执行了。

// 设置只容许执行本身网站的js脚本,ctx.set('Content-Security-Policy', "default-src 'self'")// 浏览器打开链接时4000端口的外部资源不能被加载https://127.0.0.1:3000?from=<script src="http://127.0.0.1:4000/hack.js"></script>复制代码
  1. 转译字符

用户输入永远不可信任的,最广泛的作法就是转译输出的内容,对于引号,尖括号,斜杠进行转译,好比经过以下的函数,对用户输入的内容进行转译。

function escape(str) {
    str = str.replace(/&/g, '&amp;');
    str = str.replace(/</g, '&lt;');
    str = str.replace(/>/g, '&gt;');
    str = str.replace(/"/g, '&quto;');
    str = str.replace(/'/g, '&#39;');
    str = str.replace(/`/g, '&#96;');
    str = str.replace(/\//g, '&#x2F;');return str;
}escape('<script>alert(123)</script>'); // &lt;script&gt;alert(123)&lt;&#x2F;script&gt;复制代码

这种转译叫作黑名单注意,就是把不安全的东西进行转译,好比说<>, 可是有一种状况是不能进行黑名单转译的。

有时咱们要处理一些富文本,显然不能经过上面的办法来转译全部字符,由于这样会把须要的格式也过滤掉,对于这种状况,一般采用白名单过滤的办法,固然也能够经过黑名单过滤,可是考虑到须要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。

白名单的方式就是容许一部分安全的字符经过,其余的字符所有转译,这里推荐使用xss的npm包来处理。

// 引入xssconst xss = require('xss');let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss")</script>');// <h1 id="title">XSS Demo</h1>&lt;script&gt;alert("xss")&lt;/script&gt;console.log(html);复制代码

能够看到这里xss保留了h1标签,由于他是安全的,对script标签进行了转译,由于他是不全安的。

通常状况用户输入的数据或者从url中获取的参数咱们不建议直接使用innnerHTML插入到页面中,除了xss模块和escape方法还能够引入html模板,常见的是ejs模板。react,vue,angular等框架默认已经帮咱们处理了xss。

// 转译 inputValue 内容<%= inputValue %>// 不转移 inputValue 内容<%- inputValue %>复制代码
  1. HttpOnly Cookie

为何用户的cookie能够被调取,缘由是js是能够获取cookie的,咱们能够经过禁止js访问cookie的方式防范这种***。

这是预防XSS***窃取用户cookie最有效的防护手段,Web应用程序在设置cookie时,将其属性设为HttpOnly, 就能够避免该网页的cookie被客户端恶意javaScript窃取,保护用户cookie信息。也就是服务在设置cookie的时候跟上HttpOnly便可。

response.addHeader('Set-Cookie', 'uid=112; path/; HttpOnly')复制代码

这样设置的cookie,js就没办法访问到了。

以上说的就是一些基本的防护XSS***的手段。CSP,字符转译,HttpOnly Cookie。

2.CSRF

CSRF( Cross Site Request Forgery),即跨站请求伪造,是一种常见的web***,它利用用户已登陆的身份,在用户绝不知情的状况下,以用户的名义来完成非法操做。简单来讲***步骤也很简单。

用户已经登陆了站点A, 而且在A站点记录了登陆状态(cookie),再次进来不须要登陆了。在用户没有登出站点A的状况下,也就是登陆态还有效时,访问了恶意***者提供的引诱危险站点B, B站点调用A站点的某个接口,好比说提交接口。若是A站点没有作任何的CSRF防护,就会被***。

原理也很简单,由于B站点调用了A站点的提交接口,根据cookie匹配原则,调用哪一个站点的接口就会携带哪一个站点的cookie,携带的就是用户存在A站点的cookie,这个时候提交接口传递的参数其实是B站点提供的。在用户无心识的状况下以用户的身份调用了接口。

不少人可能会以为,B站点调用A站点的接口跨域了啊,那怎么行。这没什么,跨域只是一种说法而已通常的跨域是前端拿不到接口的返回值,但不表明请求发不出去,这种***只要请求发出去了就达到***的目的了,返回值什么的都无所谓了。

防护CSRF的手段有三种。

第一个是禁止第三方网站携带Cookie,可是有兼容性问题,第二个方式是验证请求传递过来的referrer,判断是否是一个合法的referrer。其实不少的防盗链都是验证referrer的方式。

referrer就是发送请求的那个前端页面地址,能够经过referrer的方法进行屏蔽和过滤,可是他也有一个问题https是不发送referrer的,因此也算是兼容性的问题。

目前最有效的方式仍是验证码的方式或者人机交互的方式,之前能够经过CSRF调取用户资金,由于转帐比较简单,但如今基本转帐都会发送验证码之类的验证。

3.点击劫持

点击劫持是一种视觉欺骗的***手段,***者将须要***的网站经过iframe嵌套的方式嵌入本身的网页中,并将iframe设置为透明,在页面中透出一个按钮诱导用户点击。

当你点击这个按钮的时候其实是点击到了iframe中的某个按钮上,触发iframe嵌入网站的功能,好比想要给一个页面点赞,就能够把这个页面经过iframe假装。

要防护这个其实很简单,只须要设置X-FRAME-OPTIONS响应头,X-FRAME-OPTIONS是一个http响应头,在如今浏览器有一个很好的支持,这个http响应头就是为了防护用iframe嵌套的点击劫持***。

该响应头有三个值可选分别是

DENY 表示页面不容许经过iframe的方式展现

SAMEORIGIN 表示页面能够在相同域名下经过iframe的方式展现

ALLOW-FROM 表示页面能够在指定来源的iframe中展现

ctx.set('X-FRAME-OPTIONS', 'DENY')复制代码

也可直接经过js判断是否在iframe中,不过该方法也有问题,跨域状况下内层的页面是没法操做外层的location的。

if (self !== top) {
    top.location.href = self.location.href; // 将外层的location修改成内层的locationdocument.body.innnerHTML = ''; // 清除页面内容}复制代码

4.SQL注入

SQL注入是比较常见的网络***方式之一,它不是利用操做系统的BUG来实现***,而是针对程序员编写时的疏忽,经过SQL语句,实现无帐号登陆,甚至篡改数据库。SQL注入***比较偏向后端,前端同窗了解便可。

假设咱们的sql是下面这个样子的,查询数据库用户表中是否存在用户名为userName变量,密码为password变量的用户。

const sql = 'select * from user_table where username= "'+ userName +'" and password = "' + password + '"';复制代码

当用户输入了正确的用户名和密码的时候不会有什么问题

const userName = 'yd';const password = '123456';const sql = 'select * from user_table where username= "'+ userName +'" and password = "' + password + '"';// select * from user_table where username= "yd" and password = "123456"复制代码

可是若是***输入的密码是1"or"1"="1 就会出现问题, 这是一条永远能够执行成功的sql。username等于yd ,password等于或者1=1;恒成立的sql。

const userName = 'yd';const password = '1"or"1"="1';const sql = 'select * from user_table where username= "'+ userName +'" and password = "' + password + '"';// select * from user_table where username= "yd" and password = "1" or"1"="1"复制代码

通常状况下咱们是不容许拼接sql的,全部的查询语句建议使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中,既不要直接拼接SQL语句,例如Node.js中的mysqljs库中的query方法。

const sql = ` SELECT * user_table WHERE username = ? AND password = ?`res = await mysql.query(sql, [ctx.request.body.username, ctx.request.body.password]);复制代码

除此以外,要严格限制web应用的数据库的操做权限,给此用户提供仅仅可以知足其工做的最低权限,从而最大限度的减小注入***对数据库的危害,后端代码检查输入的数据是否符合预期,严格限制变量的类型,例如使用正则表达式进行一些匹配处理。对进入数据库的特殊字符(',",,<,>,&,*,;)等,进行转译处理,或编码转换**。基本上全部的后端语言都有对字符串进行转译处理的方法,好比lodash的lodash._escapehtmlchar库。

5.OS命令注入

OS命令注入和SQL注入差很少,只不过SQL注入的是针对数据库的,而OS命令注入是针对操做系统的,OS命令注入***指经过web应用,执行非法的操做系统命令达到***的目的,只要在能调用shell函数的地方就有存在被***的风险,假若调用shell时存在疏漏,就能够执行插入的非法命令。

以Node.js为例,加入在接口中须要从 github 下载用户指定的项目

const exec = require('mz/child_process').exec;const params = { /* 用户输入的参数 */};
exec(`git clone ${params.repo}/some/path`);复制代码

若是传入的参数以下会怎样

https://github.com/xx/xx.git && rm -rf /* &&复制代码

这个时候若是用户的权限很大的话,就会执行rm -rf /*, 删掉服务器中全部内容。

6.请求劫持

下面这种不是咱们前端的概念,可是很经常使用,这里也说一下,了解一下便可。

请求劫持分为两种,一种是DNS劫持,一种是HTTP劫持。

DNS服务器也就是域名服务器,他会把域名转换为ip地址,若是这个被篡改了,那跳转的网站就不是意向中的网站了。咱们电脑中以一个host文件,那就是本地DNS,若是遇到DNS劫持能够查看本地host文件是否被篡改了。

HTTP劫持比较常见,HTTP自己是明文传输,而且传输的工程中极可能中间的某一环节被篡改。好比咱们常常遇到这样的状况,咱们再火车站连接了火车站的wifi,这个时候咱们不管打开什么页面出现的都是登陆wifi的页面。这个其实就是在路由器层对你访问的站点作了篡改,都没到运营商那一环。

HTTP劫持只能升级HTTPS了,由于他自己就是明文传输。

7.DDOS

这里参考了阮一峰老师的博客[DDOS ***的防范教程]。

DDOS不是一种***,而是一大类***的总称,他有几十种类型,新的***方法还在不断发明出来,网站运行的各个环节,均可以是***目标。只要把一个环节攻破,使得整个流程跑不起来,就达到了瘫痪服务的目的。

其中比较常见的一种***是CC***。他就是简单粗暴的送来大量正常的请求,超出服务器的最大承受量,致使宕机。

我遭遇的就是CC***,最多的时候全世界大概20多个IP地址轮流发出请求,每一个地址的请求在每秒200 ~ 300次,我看访问日志的时候,就以为那些请求像洪水同样涌来,一眨眼就是一大堆,几分钟的时间,日志文件的体积就大了100MB。

说实话,这是能算小***,可是个人我的网站没有任何防御,服务器仍是跟其余人共享的,这种流量一来马上就下线了。

如今的这种DDOS***方式通常是不会到达你的服务器自己的,由于大量的请求来了之后极可能在机房路由器中就所有占满了,请求已经到不了服务器层了,通常这种状况运营商直接就会把服务器下线掉了。因此服务器层基本不容易作控制。

咱们能够备份网站,就是你要有一个备份网站,或者最低限度有一个临时主页。生产服务器万一下线了,能够马上切换到备份网站,不至于毫无办法。

备份网站不必定是全功能的,若是能作到全静态浏览,就能知足需求。最低限度应该能够显示公告,告诉用户,网站出了问题,正在全力抢修。这种临时主页建议放到带宽大,能够应对***的网站上。

还能够经过HTTP请求的拦截,若是恶意请求有特征,对付起来很简单:直接拦截它就好了,能够在硬件,服务器,防火墙中进行拦截。

HTTP 拦截有一个前提,就是请求必须有特征。可是,真正的 DDOS ***是没有特征的,它的请求看上去跟正常请求同样,并且来自不一样的 IP 地址,因此无法拦截。这就是为何 DDOS 特别难防的缘由。

DDOS ***的成本仍是比较高的,咱们能够经过宽带扩容 + CDN的方式来提升***成本。

8 .爬虫

爬虫能够爬取网站中的内容,Node中可使用cheerio和https模块进行演示。

const cheerio = require('cheerio');const https = require('https');let html = '';const $ = '';

https.get('url', res => {
    res.on('data', data => {
        html += data; // 保存返回的数据});
    res.on('finish', () => {
        $ = cheerio.load(html); // cheerio解析数据// $就是拿到的dom树, 想jq同样。})
})复制代码

cheerio用法相似于jquery,https能够发送https请求。在finish方法中表示获取到了页面的html。

防护爬虫的方式比较多样。好比说验证浏览器的UA,referrer 或者验证码。还有好比查看单位时间的访问次数,访问量。

还能够进行关键信息使用图片混淆,好比说有些文字咱们直接让接口返回图片进行渲染。自己SPA单页面就是一种反爬取的手段,不过他最大的一个缺点就是对搜索引擎不友好。搜索引擎用的就是爬虫技术。因此后面又推出了***渲染来解决这个问题。

还有一些比较高级的防护手段,就是前端的一些技术限制。

字体乱序法,服务返回给前端的html中,文字和用户实际看到的不一致,好比说服务返回的div总内容是4998,而页面真正展现的是1995,他的作法也很简单,使用一个特殊的字体库,由于字体渲染的时候会去查找字体库,以字体库的样子渲染。在这个字体库中,4对应1,8对应5,就能够了。

还能够将网站重要的字体,生成图片,经过iconfont的方式来渲染。

还有一种canvas指纹反爬方法,canvas指纹的含义是,由于不一样硬件对canvas支持不一样,所以你只要画一个很复杂的canvas,那么得出的image,老是存在像素级别的偏差。考虑到爬虫代码都是统一的,就算起selenium,也是ghost的,所以指纹通常都是一致的,所以绕过概率很是低。但事实上并非如此,国内公司一般是IT统一装机,不管是软件仍是硬件都惊人的一致。因此canvas指纹类似度特别高。

最后你们能够自行了解一下无头浏览器, 这东西真的是个神器。


欢迎关注,更多内容持续更新

相关文章
相关标签/搜索