前端安全性问题

1、xss跨站脚本攻击(原理、如何进行的、防御手段是什么,要说清楚)

2、CSRF跨站请求伪造(如何伪造法?怎么防御?等等都要说清楚)

3、sql脚本注入(注入方式,防御方式)

4、上传漏洞 (防御方式)

1.xss攻击

xss攻击又叫做跨站脚本攻击,主要是用户输入或通过其他方式,向我们的代码中注入了一下其他的js,而我们又没有做任何防范,去执行了这段js。

可能用户会写一个死循环,将我们的页面给弄崩了,但是也有可能通过这种方式,来获取我们的cookie,从而回去登陆态等信息

xss攻击从来源可分为反射型和存储型

反射型:

将xss代码通过url来注入

index.html

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>反射型</title> </head> <body> <div id="test"></div> <script> var $test = document.querySelector('#test');; $test.innerHTML = window.location.hash </script> </body> </html> 

在IE浏览器去访问该页面并在地址后面加上index.html#<img src="404.html" onerror="alert('xss')" />

这时页面一打开就会有个xss的弹窗,这就是最简单的反射型攻击
当然可能会觉得这样没有任何作用,但是修改一下代码

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>反射型</title> </head> <body> <div id="test"></div> <script> // 先向页面的cookie存储一个name=1的信息 document.cookie = "name=1" var $test = document.querySelector('#test');; $test.innerHTML = window.location.hash </script> </body> </html> 

此时打开的地址修改为index.html#<img src="404.html" onerror="alert(document.cookie)" />

这里就会发现弹窗内容为我们存取的cookie。

注意:1.这里必须用IE打开这个链接,因为chrome和safari等浏览器,会主动将url里的一下字符串进行encode,保证了一定的安全性。 2.为什么我们这里用img的onerror来注入脚本呢?而不是直接用script标签来执行,我们修改一下访问的地址index.html#<script>alert(document.cookie)</script>,这时会发现,页面并没有执行这段代码,但是这段代码已经注入到了#test标签中了。所以,一般通过img的onerror来注入是最有效的方法

存储型

将xss代码发送到了服务器,在前端请求数据时,将xss代码发送给了前端。

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>存储型</title> </head> <body> <div id="test"></div> <script> // 先向页面的cookie存储一个name=1的信息 document.cookie = "name=1" // 这里假设是请求了后台的接口 response是我们请求回来的数据 var response = '<img src="404.html" onerror="alert(document.cookie)"' var $test = document.querySelector('#test');; $test.innerHTML = response </script> </body> </html> 

这里最常见的情况就是一个富文本编辑器下,由用户输入了一串xss代码,存储在了服务器中,我们在展示用户输入内容时,没有做防范处理。

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>富文本</title> </head> <body> <div id="test"></div> <textarea name="" id="" cols="30" rows="10"></textarea> <button onclick="submit()">提交</button> </body> </html> <script> function submit() { var $test = document.querySelector('#test'); $test.innerHTML = document.querySelector('textarea').value } </script> 

xss的防范手段:

1.encode

encode也分为html的encode和js的encode

html的encode: 就是将一些有特殊意义的字符串进行替换,比如:

& => &amp;

" => &quot;

' => &#39;

< => &lt;

> => &gt;

通过这些字符的替换,之前我们输入的<img src="null" onerror="alert()">就被encode成了&lt;img src=&quot;null&quot; onerror=&quot;alert()&quot;&gt;

js的encode: 使用“\”对特殊字符进行转义,除数字字母之外,小于127的字符编码使用16进制“\xHH”的方式进行编码,大于用unicode(非常严格模式)

用“\”对特殊字符进行转义,这个可能比较好理解,因为将一下,比如',"这些字符转译为',"就可以使得js变为一个字符串,而不是一个可执行的js代码了,那为什么还需要进行16进制转换和unicode转换呢?这样做是为了预防一下隐藏字符,比如换行符可能会对js代码进行换行

//使用“\”对特殊字符进行转义,除数字字母之外,小于127使用16进制“\xHH”的方式进行编码,大于用unicode(非常严格模式)。
var JavaScriptEncode = function(str){ var hex=new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); function changeTo16Hex(charCode){ return "\\x" + charCode.charCodeAt(0).toString(16); } function encodeCharx(original) { var found = true; var thecharchar = original.charAt(0); var thechar = original.charCodeAt(0); switch(thecharchar) { case '\n': return "\\n"; break; //newline case '\r': return "\\r"; break; //Carriage return case '\'': return "\\'"; break; case '"': return "\\\""; break; case '\&': return "\\&"; break; case '\\': return "\\\\"; break; case '\t': return "\\t"; break; case '\b': return "\\b"; break; case '\f': return "\\f"; break; case '/': return "\\x2F"; break; case '<': return "\\x3C"; break; case '>': return "\\x3E"; break; default: found=false; break; } if(!found){ if(thechar > 47 && thechar < 58){ //数字 return original; } if(thechar > 64 && thechar < 91){ //大写字母 return original; } if(thechar > 96 && thechar < 123){ //小写字母 return original; } if(thechar>127) { //大于127用unicode var c = thechar; var a4 = c%16; c = Math.floor(c/16); var a3 = c%16; c = Math.floor(c/16); var a2 = c%16; c = Math.floor(c/16); var a1 = c%16; return "\\u"+hex[a1]+hex[a2]+hex[a3]+hex[a4]+""; } else { return changeTo16Hex(original); } } } var preescape = str; var escaped = ""; var i=0; for(i=0; i < preescape.length; i++){ escaped = escaped + encodeCharx(preescape.charAt(i)); } return escaped; } 

2.对于富文本的防范:filter

因为富文本是比较特殊的,在富文本中输入标签,我们需要展示出来,所以我们不能用之前的html的encode方法来执行。所以我们就得用一个叫白名单过滤的方式来防范。

原理就是:首先列举一下比较合法的标签,称为白名单,这些标签是不会对页面进行攻击的。之后对用户输入的内容进行白名单过滤。

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>富文本</title> </head> <body> <div id="test"></div> <textarea name="" id="" cols="30" rows="10"></textarea> <button onclick="submit()">提交</button> </body> </html> <!-- xss_filter.js是一个白名单过滤库 --> <script src="./xss_filter.js"></script> <script> function submit() { var $test = document.querySelector('#test'); $test.innerHTML = filterXSS(document.querySelector('textarea').value) } </script> 

此时用户如果提交<img src="null" onerror="alert()">就会被过滤成<img src="">

这样就有效的防范了用户输入的xss代码

注意: 当遇到想后台提交数据的情况,我们应该在用户提交的时候就进行过滤和encode呢?还是展示的时候处理呢? 我们应当考虑到提交代码后会有个多端展示的问题,可能我们web端需要进行这些处理,但是移动端展示的时候就不需要这些处理,所以我们应当在展示的时候进行处理,而不是录入的时候处理

2.CSRF– 跨站伪造请求

CSRF就是利用你所在网站的登录的状态,悄悄提交各种信息, 是一种比xss还要恶劣很多的攻击。因为CSRF可以在我们不知情的情况下,利用我们登陆的账号信息,去模拟我们的行为,去执行一下操作,也就是所谓的钓鱼。比如我们在登陆某个论坛,但这个网站是个钓鱼网站,我们利用邮箱或者qq登陆后,它就可以拿到我们的登陆态,session和cookie信息。然后利用这些信息去模拟一个另外网站的请求,比如转账的请求。

 
836049-20160322214747901-1548153978.jpg

csrf.html

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>csrf</title> </head> <body> <iframe id="" name="csrf-form"></iframe> <form target="csrf-form" method="post" action="http://127.0.0.1:3001/csrf"> <input name="name" value="1111"> <input type="submit" value="提交"> </form> </body> </html> 

我们点击进入了一个csrf这个页面里,我们以为我们只是在csrf中点击提交了1111这个信息,其实这个网站悄悄的把这些信息提交到了本地的csrf上了,而不是我们当前浏览的csrf.html中

server.js

const http = require('http'); const fs = require('fs'); const proxy = http.createServer((req, res) => { if(req.method == 'POST'){ req.on('data' , (data)=>{ console.log('referer :' , req.headers.referer); console.log('data :' , data.toString() , ' cookies:' , req.headers.cookie); }); req.on('end' , (data)=>{ res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(''); }) } else { res.setHeader('Set-Cookie', ['login=1']); res.end(''); } }).listen(3001); 

在命令行中输入node server.js
这是一个简单的服务,端口为3001,如果我们直接本地登陆localhost:3001会给我们本地注入一个cookie为login=1的登陆态
此时我们在访问csrf.html,在点击提交按钮的时候,会发现会把这个登陆态也提交上去。这就是一个典型的钓鱼网站,

防范措施

  1. 提交 method=Post 判断referer
    HTTP请求中有一个referer的报文头,用来指明当前流量的来源参考页。如果我们用post就可以将页面的referer带入,从而进行判断请求的来源是不是安全的网站。但是referer在本地起的服务中是没有的,直接请求页面也不会有。这就是为什么我们要用Post请求方式。直接请求页面,因为post请求是肯定会带入referer,但get有可能不会带referer。

  2. 利用Token
    Token简单来说就是由后端生成的一个唯一的登陆态,并传给前端保存在前端,每次前端请求时都会携带着Token,后端会先去解析这个Token,看看是不是后台给我们的,已经是否登陆超时,如果校验通过了,才会同意接口请求



作者:鱼仔1234
链接:https://www.jianshu.com/p/a38e280ed48b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

三:sql攻击

定义:输入参数未经过滤,然后直接拼接到sql语句当中,解析执行,达到预想之外的效果称为sql攻击

举个栗子:下面这种情况:我在输入用户账号的时候,在后面加入了一个#号

 
 

这样如果后代的执行 的mysql语句就会是这样:                                                                                                  select * from userdatabase where username=1550976562# and password=' ',使用过mysql的用户都知道#号是mysql的注释,这样后面的 and password=' '就会被当做注释,不会被执行,因此攻击者就可以不用密码登录你的网站了。

对SQL注入的防御方法主要有:

1. 字符串长度验证,仅接受指定长度范围内的变量值。sql注入脚本必然会大大增加输入变量的长度,通过长度限制,比如用户名长度为 8 到 20 个字符之间,超过就判定为无效值。

2. 对单引号和双"-"、下划线、百分号等sql注释符号进行转义

3. 对接收的参数进行类型格式化,如id参数值获取后,进行int类型转换

4. 永远不要使用动态拼装SQL,推荐使用参数化的SQL或者直接使用存储过程进行数据查询存取。sql注入最主要的攻击对象就是动态拼装的SQL,通过参数化查询可以极大减少SQL注入的风险。

5. 永远不要使用管理员权限的数据库连接(sa、root、admin),为每个应用使用单独的专用的低特权账户进行有限的数据库连接。

6. 不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。这样对方就算获取到整个表的数据内容,也没什么价值。

7. 应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装,把异常信息输出到日志而不是在页面中展示。

8. 做好XSS跨站攻击的防护,防止攻击者伪造管理员信息进入系统后台

9. 不管客户端是否做过数据校验,在服务端必须要有数据校验(长度、格式、是否必填等等)



作者:15545985473
链接:https://www.jianshu.com/p/ee24eafe0e9e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 
四. 上传漏洞
 

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。文件上传功能本身是一个正常的业务需求,对于网站来说,很多时候也确实需要用户将文件上传到服务器。所以文件上传本身没有问题,但又问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做得不够安全,则会导致严重的后果。----摘自《白帽子讲WEB安全》

一、漏洞成立的条件

1、上传的文件能够被WEB容器解释执行。
2、用户能够从web上访问这个文件。如果文件上传了,但用户无法通过web访问,或者无法使得web容器解释这个脚本,那么也不能称之为漏洞。

二、常见防御措施及软肋

1、在前端验证文件扩展名

​ 通过这种方式的验证,绕过方式有二:

(1)客户端禁用JS脚本

​ 禁用JS脚本,这就使得验证文件的功能失效,用户可上传任意的文件。

(2)通过抓包改包方式

​ 假如前端限制了只允许上传png格式的文件。我们首先将一句话木马文件后缀名更改为png后上传。此时会绕过前端js的验证,绕过验证后,通过抓包,修改报文中文件名的后缀,使其还原。显然,一句话木马上传成功。

2、在服务端验证文件类型

​ 在服务端验证文件类型,一般是校验Content-type字段的值。同样,通过抓包改包可成功绕过其验证。

3、在服务端验证文件后缀名

(1)黑名单校验

​ 黑名单校验方式极不靠谱,我们总会找到一些漏网之鱼,也有可能存在一些大小写绕过的方式。比如 aSp 和 pHp 之类的。

(2)白名单校验

​ 白名单校验,其防御能力相对于黑名单校验,要更安全,增加了攻击者的攻击难度。但是白名单也有其软肋之处:如果服务器存在解析漏洞或截断,则会成功触发漏洞。如:

A:0x00 截断绕过

​ 用像test.asp%00.jpg的方式进行截断,属于白名单文件。由于存在0x00,服务器会认为是asp文件。

B:解析/包含漏洞绕过

​ 这类漏洞直接配合上传一个代码注入过的白名单文件即可,再利用解析,包含漏洞。

4、在服务端验证文件内容

​ 验证文件内容,加大了攻击者的攻击难度。但在一定条件下,也有绕过的可能。其绕过方式有二:

(1)制作图片马

(2)文件幻术头绕过

三、总结

​ 以上这些防御措施,如果在一定的限制条件下,是“安全的”。如果超过了安全边界,则会变得那么不安全。对于文件上传漏洞,我们只要知道它成立的条件,则可在一定程度上进行防御。其总结如下:

1、上传后的文件最好不可执行。

2、更改上传后的文件名,不与上传之前的文件名相同。

3、如非必要,不要暴漏文件的访问路径。



作者:无远弗届_90
链接:https://www.jianshu.com/p/6d16b6c622d6
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自www.cnblogs.com/fs0196/p/12643367.html