今天接到了滴滴的一面电面,希望这次可以通过啊,真的不想再死于一面了。
面试过程中有几处没有答出来,其中一个就是跨域,只讲了JSONP和CORS(跨域资源共享),CORS也只是模模糊糊答了一部分,个人感觉并没有达到点上。
回去又好好看了一下,发现还真的有好多可以说的啊,那现在就让我们开始吧~
同源策略
”不同源的站点之间相互请求会做限制“是浏览器的行为,同源指的是协议、域名、端口都相同,脚本不能访问不同源的资源。
前端解决跨域问题
①document.domain+ iframe
只有子域名向父域名请求时才可以用,而且iframe还要设置display为none,底下的代码中document.domain设置此时的主域名。什么是主域名呢?主域名只有一个点号:'a.com'类似这种。与之相对的是子域名:'script.a.com'可以有好几个点号。
document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
//在这里操作doc,也就是b.html
ifr.onload = null;
};
②location.hash+iframe
改变hash值并不会导致页面刷新,所以可以利用hash值来进行数据传递。a.com主域名下的cs1.html要和b.com主域名下的cs2.html进行数据传递,cs1.html创建一个隐藏的iframe(src指向cs2.html),此时的hash值可以用来传递数据(小);cs2.html收到数据后可以通过修改cs1.html的hash值来传递数据,同时cs1.html上有一个定时器,隔一段时间判断location.hash的值有没有变化,一旦有变化就获取hash。
// a.com域名下的cs1.html
function srartRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://b.com/cs2.html';
document.body.appendChild(ifr);
}
function checkHsh(){
try{
var data = location.hash?location.hash.substring(1):'';
console.log('The data is'+data);
}catch(e){
console.log('The error is'+e);
}
}setInterval(checkHsh,2000);
// b.com域名下的cs2.html
switch(location.hash){
case '#123':
callback();
break;
case '#456':
//do sth
break;
}
//回调函数用于修改location.hash
function callback(){
try {
parent.location.hash = '一些data';
}catch(e){
//ie chrome下无法自己改parent的hash所以还是要借助一个iframe
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://a.com/cs3.html';
document.body.appendChild(ifr);
}
}
//在a.com的cs3.html中
parent.parent.location.hash = self.location.hash.substring(1);
③postMessage
HTML5中新增的方法,实现跨域通信。
//发送窗口
var iframe = window.frames["sendMessage"];
//使用iframe的window向iframe发送message
iframe.onload = function(){
iframe.postMessage('给你钱儿砸', "*");
}
window.onmessage = function(e){
alert(e.data);
}
这里有两个坑,一个是必须运行在服务器环境下,一个是对iframe的postMessage必须等到iframe已经load完,否则无效。
发送的方法为otherWindow.postMessage(message, targetOrigin)。其中otherWindow就是目的窗口,targetOrigin就是目的域。
//接收窗口
window.addEventListener('message',function(e){
console.log(e.source, e.data, e.origin);
e.source.postMessage("收到了爹", e.origin);
}, false)
接收的方法为监听message事件,获取事件event的data、source和origin属性。source就对应发送方窗口,而origin就对应发送方的域。
④WebSocket
HTTP:通信只能由客户端发起,无法做到服务器主动向客户端推送消息。
WebSocket也是基于TCP协议的,服务器端好实现;默认端口也是80(HTTP)和443(HTTPS),握手阶段采用的是HTTP,所以可以通过各种HTTP代理服务器;数据小;没有同源限制。
//1.新建WebSocket实例,客户端与服务器进行连接
var ws = new WebSocket("http://a.com/cs1.html");
//2.onopen属性指定连接成功后的回调函数
ws.onopen = function(){
//do sth
ws.send('These are some data');
};
//3.onmessage属性指定收到服务器数据之后的回调函数
ws.onmessage = function(event){
var data = event.data;
//处理数据
};
//4.onclose指定连接关闭之后的回调函数
ws.onclose = function(){
//do sth
}
//5.bufferedAmount表示还有多少字节的二进制数据没发出去
if(ws.bufferedAmount === 0){
//发送完毕
}else{
//发送还未完成
}
//6.onerror指定报错时的回调函数
ws.onerror = function(){
//do sth
}
JS创建了WebSocket之后会发送一个HTTP请求到服务器,取得响应后建立的连接会直接从HTTP变为WebSocket协议。
接下来我们说安全问题~
XSS攻击 :有三方“用户、服务器、攻击者”,攻击者在用户所访问的网页中插入自己的脚本,这段脚本会在用户浏览器中执行,攻击者从而获取用户(比如cookie)信息。因为最后把用户信息发到攻击者自己的网站(和服务器不是一个站),所以叫跨站脚本攻击。
存储型: 数据库中存有的数据,被XSS攻击,返回给客户端。攻击者通过留言、评论、博客的方式,将恶意代码注入到服务器。
反射型:用户输入的,被XSS攻击,发送给后台,后台并未存储也并未过滤,直接“反射”给了客户端。一般攻击者会发送邮件或者聊天软件,用户点击,从而达到XSS攻击。
DOM:根据用户的输入动态构建dom,如果没有对用户的输入进行过滤就会导致受到XSS攻击。DOM-XSS是通过url传入参数控制触发的。
XSS防御办法:
a.对输入和url参数进行过滤,将容易导致XSS攻击的半角字符替换成全角,黑名单就是谁不能出现,白名单就是只能出现谁。前端后端都要过滤。
b.对输出进行转义,对潜在威胁的字符使用编码或者转义的方式,&<>"'/等字符。
c.带有HttpOnly属性的Cookie浏览器可以访问,js脚本不能访问。
CSRF攻击:用户打开浏览器访问信任网站A并输入了用户名和密码,A返回用户Cookie信息。此时用户在没有登出A网站的情况下在同一个浏览器中打开了网站B,B返回一些攻击代码并向A发出请求。这个请求因为是带着用户的Cookie,所以网站A会误认为是用户发来的从而接受请求。
CSRF防御办法:
a.验证HTTP Referer字段。记录该HTTP请求的来源地址。比如银行转账,我们只有先登录账号,才能进行转账,那进行转账时的请求头Referer字段一定是这个网站的名字;而如果是攻击者,他的请求头Referer字段一定是他们自己的地址。
b.给HTTP头增加自定义属性token。还拿转账来打比方吧。登录银行网站时服务器会签发一个token并发给客户端,客户端每次发送请求时都会带着这个token,服务器会进行验证。
c.二维码