前端的安全问题

前端的安全问题,是一个很容易被大家忽略的问题。也是一个很难项目话的问题。

前端安全问题主要分为以下几点:

1.xss攻击

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

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

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

反射型:

将xss代码通过url来注入

index.html




    
    反射型


在IE浏览器去访问该页面并在地址后面加上index.html#

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




    
    反射型


此时打开的地址修改为index.html#

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

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

存储型

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




    
    存储型


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




    
    富文本


  

xss的防范手段:

1.encode

encode也分为html的encode和js的encode

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

& => &

" => "

' => '

< => <

> => >

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

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方法来执行。所以我们就得用一个叫白名单过滤的方式来防范。

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




    
    富文本


  

此时用户如果提交就会被过滤成

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

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

2.CSRF– 跨站伪造请求

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

836049-20160322214747901-1548153978.jpg

csrf.html




    
    csrf



我们点击进入了一个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,看看是不是后台给我们的,已经是否登陆超时,如果校验通过了,才会同意接口请求

你可能感兴趣的:(前端的安全问题)