首页 文章 精选 留言 我的

精选列表

搜索[专家兼容测试],共10000篇文章
优秀的个人博客,低调大师

AI+SQLazy:从 SQL 小白到专家的神器

SQL 看着像英语,但其实根本不是一回事。一句话能说清的需求,落到 SQL 里就是几十行嵌套,语法还挑剔,小白看一眼就想放弃。 AI 来了,总算能“写”SQL 了。把需求讲给 AI,SQL 马上出来。可然后呢?读不懂。同一句话,每次问 AI,给你的 SQL 还不一样。改一次需求,它又生成一版全新的,之前看的、改的全都白费。写了很久,还是小白。

优秀的个人博客,低调大师

英特尔聘请 Linux/BSD 性能专家 Brendan Gregg

近日,英特尔 CTO Greg Lavender 在推特宣布,Brendan Gregg 已加入英特尔的软件团队,将专注于英特尔 xPU 计算领域方面的工作。 Brendan Gregg 在 Linux 和 BSD 性能分析方面有着极深的造诣,并开发了许多相关工具。加入英特尔前,他就职于 Netflix,为视频网站的的需求做了大量的开源优化工作。多年来,Brendan Gregg 还在其他多个主要组织工作过,包括在 Sun Microsystems 的 DTrace、参与 ZFS 开发,对 (e)BPF 也有影响,并撰写了各种与性能相关的书籍,以及其他成就。

优秀的个人博客,低调大师

隐私专家呼吁调查谷歌:未经允许追踪 Android 用户

据报道,隐私维权者马克斯 · 施雷姆斯(Max Schrems)今日向法国监管机构投诉谷歌,指控谷歌在未经许可的情况下,私自跟踪 Android 手机用户。 施雷姆斯成立的隐私维权组织 “Noyb”今日在法国投诉谷歌,指控谷歌在创建独特的广告代码时,没有获得 Android 手机用户的许可。为此,他呼吁相关部门对谷歌展开调查。Noyb 称:“这些追踪器显然需要征得用户同意,但谷歌忽视了这一法律要求。” 谷歌广告代码的工作原理,类似于苹果公司的 “广告客户识别码”(IDFA),允许谷歌在不同网站上跟踪用户,并根据他们的浏览历史投放广告。 对此,谷歌尚未发表评论。 之前,施雷姆斯以起诉 Facebook 而闻名。数年前,施雷姆斯在一个里程碑式的案件中与 Facebook 展开了较量。最终,这起案件导致监管机构对美国和欧洲之间的数据传输协议做出了关键性决定。 去年夏天,欧洲最高法院决定驳回与美国达成的数据共享协议,原因是担心美国的监控法影响过于深远。当时。施雷姆斯将其形容为 “对爱尔兰数据监管机构和 Facebook 的彻底打击”。 去年 11 月,施雷姆斯还曾向德国和西班牙的数据保护机构投诉苹果,称 iPhone 在未经用户同意的情况下存储用户数据,这违反了欧盟法律。而苹果表示,该案中的指控是不准确的。 【责任编辑:未丽燕 TEL:(010)68476606】

优秀的个人博客,低调大师

JavaScript技术专家晋升考试题,敢应战吗?

题库地址:http://javascript-puzzlers.herokuapp.com/ 1. 这段代码的执行结果? vara=Function.length,b=newFunction().lengtha===b 这段代码的执行结果? 答案:false解析:首先new在函数带()时运算优先级和.一样所以从左向右执行newFunction()的函数长度为0巩固:functionfn(){vara=1;}console.log(fn.length)//0fn和newFunction()一样 2. [typeof null, null instanceof Object] 答案:["object",false]解析:null代表空对象指针,所以typeof判断成一个对象。可以说JS设计上的一个BUGinstanceof实际上判断的是对象上构造函数,null是空当然不可能有构造函数巩固:null==undefined//truenull===undefined//flase 3. [ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ] 答案:an error解析:Math.pow(x,y)x的y次幂的值reduce(fn,total)fn(total,currentValue,currentIndex,arr)如果一个函数不传初始值,数组第一个组默认为初始值.[3,2,1].reduce(Math.pow)Math.pow(3,2)//9Math.pow(9,1)//9巩固:[].reduce(Math.pow)//空数组会报TypeError[1].reduce(Math.pow)//只有初始值就不会执行回调函数,直接返回1[].reduce(Math.pow,1)//只有初始值就不会执行回调函数,直接返回1[2].reduce(Math.pow,3)//传入初始值,执行回调函数,返回9 4. 这段代码的执行结果 varval='smtg';console.log('Valueis'+(val==='smtg')?'Something':'Nothing'); 这段代码的执行结果? 答案:Something解析:字符串连接比三元运算有更高的优先级所以原题等价于'Valueistrue'?'Somthing':'Nonthing'而不是'Valueis'+(true?'Something':'Nonthing')巩固:1||fn()&&fn()//11||1?2:3;//2 5. 这段代码的执行结果? varname='World!';(function(){if(typeofname==='undefined'){varname='Jack';console.log('Goodbye'+name);}else{console.log('Hello'+name);}})(); 这段代码的执行结果? 答案:Goodbye Jack解析:(1)typeof时 name变量提升。在函数内部之声明未定义(2)typeof优先级高于===巩固:varstr='World!';(function(name){if(typeofname==='undefined'){varname='Jack';console.log('Goodbye'+name);}else{console.log('Hello'+name);}})(str);答案:Hello World 因为name已经变成函数内局部变量 6. 这段代码的执行结果? varEND=Math.pow(2,53);varSTART=END-100;varcount=0;for(vari=START;i<=END;i++){count++;}console.log(count); 这段代码的执行结果? 答案:other ,不是101解析:js中可以表示的最大整数不是2的53次方,而是1.7976931348623157e+308。2的53次方不是js能表示的最大整数而应该是能正确计算且不失精度的最大整数,巩固:varEND=1234567635;varSTART=END-1024;varc=count=0;for(vari=START;i<=END;i++){c=count++;}console.log(count);//1025console.log(c);//1024 7. 这段代码的执行结果? varary=[0,1,2];ary[10]=10;ary.filter(function(x){returnx===undefined;}); 这段代码的执行结果? 答案:[]解析:filter()不会对空数组进行检测。会跳过那些空元素巩固:varary=[0,1,2,undefined,undefined,undefined,null];ary.filter(function(x){returnx===undefined;});//[undefined,undefined,undefined] 8. 这段代码的执行结果? vartwo=0.2varone=0.1vareight=0.8varsix=0.6[two-one==one,eight-six==two] 这段代码的执行结果? 答案:[true,false]解析:IEEE 754标准中的浮点数并不能精确地表达小数巩固:vartwo=0.2;varone=0.1;vareight=0.8;varsix=0.6;(eight-six).toFixed(4)==two//true 9. 这段代码的执行结果? functionshowCase(value){switch(value){case'A':console.log('CaseA');break;case'B':console.log('CaseB');break;caseundefined:console.log('undefined');break;default:console.log('Donotknow!');}}showCase(newString('A')); 这段代码的执行结果? 答案:Do not know!解析:switch判断的是全等(===),newString(x)是个对象巩固:vara=newString('A');a.__proto__//String.prototype实例的原型指向构造函数的原型对象 10. 这段代码的执行结果? functionshowCase2(value){switch(value){case'A':console.log('CaseA');break;case'B':console.log('CaseB');break;caseundefined:console.log('undefined');break;default:console.log('Donotknow!');}}showCase2(String('A')); 这段代码的执行结果? 答案:Case A解析:String('A')就是返回一个字符串巩固:vara2='A';a2.__proto__//String.prototypea1.__proto__===a2.__proto__//true上一题的a.__proto__那字符串不是对象为啥也指向String.prototype?解析:b是基本类型的值,逻辑上不应该有原型和方法。为了便于操作,有一种特殊的引用类型(基本包装类型)String。其实读取时,后台会自动完成下面的操作:varstr=newString("A");//创建实例str.__proto__;//调用指定属性和方法str=null;//销毁实例所以a1.__proto__===a2.__proto__但注意基本包装类型特殊就在于它对象(str)的生命周期,只存在于一行代码(a1.__proto__=== a2.__proto__)的执行瞬间。这也就解释了为啥字符串也能操作属性和方法但不能添加。基本包装类型有三个(String,Number,Boolean)(详情请看《js高程》5.6基本包类型P119) 11.这段代码的执行结果? functionisOdd(num){returnnum%2==1;}functionisEven(num){returnnum%2==0;}functionisSane(num){returnisEven(num)||isOdd(num);}varvalues=[7,4,'13',-9,Infinity];values.map(isSane); 这段代码的执行结果? 答案:[true,true,true,false,false]解析:%如果不是数值会调用Number()去转化'13'%2//1Infinity%2//NaNInfinity是无穷大-9%2//-1巩固:9%-2//1余数的正负号随第一个操作数 12. 这段代码的执行结果? parseInt(3,8)parseInt(3,2)parseInt(3,0) 这段代码的执行结果? 答案:3 NaN 3解析:2进制不可能有3 13. 这段代码的执行结果? Array.isArray(Array.prototype) 这段代码的执行结果? 答案:true解析:Array.prototype是一个数组数组的原型是数组,对象的原型是对象,函数的原型是函数 14. 这段代码的执行结果? vara=[0];if([0]){console.log(a==true);}else{console.log("wut");} 这段代码的执行结果? 答案:false解析:[0]的boolean值是trueconsole.log(a==true);//转换为数字进行比较,a转换先toString,转化成'0',再Number('0')转化成数值0Number(true)=>1,所有是false 15.[]==[] 答案:false解析:两个引用类型,==比较的是引用地址巩固:[]== ![](1)!的优先级高于==,右边Boolean([])是true,取返等于false(2)一个引用类型和一个值去比较把引用类型转化成值类型,左边0(3)所以0==false答案是true 16. '5'+3'5'-3 这段代码的执行结果? 答案:53 2解析:加号有拼接功能,减号就是逻辑运算巩固:typeof (+"1")//"number"对非数值+—常被用来做类型转换相当于Number() 17. 1 + - + + + - + 1 答案:2解析:+-又是一元加和减操作符号,就是数学里的正负号。负负得正哈。巩固:一元运算符还有一个常用的用法就是将自执行函数的function从函数声明变成表达式。常用的有+-~!void+function(){}-function(){}~function(){}voidfunction(){} 18. 这段代码的执行结果? varary=Array(3);ary[0]=2ary.map(function(elem){return'1';}); 这段代码的执行结果? 答案:["1",empty×2]解析:如过没有值,map会跳过不会执行回调函数 19. 这段代码的执行结果? functionsidEffecting(ary){ary[0]=ary[2];}functionbar(a,b,c){c=10sidEffecting(arguments);returna+b+c;}bar(1,1,1) 这段代码的执行结果? 答案:21,解析:arguments会和函数参数绑定。巩固:但如果es6付给初始值则无法修改,因为es6编译后用了严格模式functionsidEffecting(ary){ary[0]=ary[2];}functionbar(a=1,b,c){c=10sidEffecting(arguments);returna+b+c;}bar(1,1,1)//12这里总结一下:严格模式和非严格模式(1)严格模式arguments对象是传入函数内实参列表的静态副本;非严格模式下,指向同一个值的引用(2)严格模式变量必须先声明,才能使用(3)严格模式中callapply传入nullundefined保持原样不被转换为window 20. 这段代码的执行结果? vara=111111111111111110000,b=1111;a+b; 这段代码的执行结果? 答案:11111111111111111000解析:在JavaScript中number类型在JavaScript中以64位(8byte)来存储。这64位中有符号位1位、指数位11位、实数位52位。2的53次方时,是最大值。其值为:9007199254740992(0x20000000000000)。超过这个值的话,运算的结果就会不对. 21. 这段代码的执行结果? varx=[].reverse;x(); 这段代码的执行结果? 答案:error解析:原来答案是windowx=[].reverse是把reverse函数赋值给xreverse函数处理的是调用它的this比如[1,2,3].reverse()时,它的this是[1,2,3]以前reverse是非严格模式的函数下,没传this会默认为window现在的reverse使用严格模式编写,应该是undefined,所以会报类型转换错误 22.Number.MIN_VALUE > 0 答案:true解析:MIN_VALUE 属性是 JavaScript 中可表示的最小的数(接近0,但不是负数)。它的近似值为5x10-324。 23.[1 < 2 < 3, 3 < 2 < 1] 答案:[true,true]解析:1<2=>true;true<3=>1<3=>true;3<2=>false;false<1=>0<1=>true; 24. 2 == [[[2]]] 答案:true解析:值和引用类型去比较,把引用类型转话成值类型[[[2]]])//2巩固:++[[]][+[]]+[+[]]//"10"(1)(++([[]][+[]]))+[+[]]//运算符权重判断,安利一下第四题下面的文章(2)(++([[]][0]))+[0]//16题中我们讲过+用来做类型转换Number([])===0(3)+([]+1)+[0]//[[]]数组的第0项就是[],++代表自增+1*******注意这一步不是(++[])+[0]这样是错误的**********(4)+([]+1)+[0]//前面+将"1"转成数字1后边,+是拼接"0"所以是字符串"10"这题的详细解释在下面的链接中。高票答案解释的非常赞,推荐阅读 25. 这段代码的执行结果? 3.toString()3..toString()3...toString() 这段代码的执行结果? 答案:error, "3",error解析:因为在 js 中1.1,1.,.1都是合法的数字.那么在解析3.toString的时候这个.到底是属于这个数字还是函数调用呢?只能是数字,因为3.合法啊! 26. 这段代码的执行结果? (function(){varx=y=1;})();console.log(y);console.log(x); 这段代码的执行结果? 答案:1,error解析:y 被赋值成全局变量,等价于y=1;varx=y; 27. 这段代码的执行结果? vara=/123/,b=/123/;a==ba===b 这段代码的执行结果? 答案:false,false解析:正则是对象,引用类型,相等(==)和全等(===)都是比较引用地址 28. 这段代码的执行结果? vara=[1,2,3],b=[1,2,3],c=[1,2,4]a==ba===ba>ca<c 这段代码的执行结果? 答案:false,false,false,true解析:相等(==)和全等(===)还是比较引用地址引用类型间比较大小是按照字典序比较,就是先比第一项谁大,相同再去比第二项。 29. 这段代码的执行结果? vara={},b=Object.prototype;[a.prototype===b,Object.getPrototypeOf(a)===b] 这段代码的执行结果? 答案:false,true解析:Object的实例是a,a上并没有prototype属性a的__poroto__指向的是Object.prototype,也就是Object.getPrototypeOf(a)。a的原型对象是b 30. 这段代码的执行结果? functionf(){}vara=f.prototype,b=Object.getPrototypeOf(f);a===b 这段代码的执行结果? 答案:false解析:a是构造函数f的原型:{constructor:ƒ} b是实例f的原型对象:ƒ(){[native code]} 31. 这段代码的执行结果? functionfoo(){}varoldName=foo.name;foo.name="bar";[oldName,foo.name] 这段代码的执行结果? 答案:["foo","foo"]解析:函数的名字不可变. 32."1 2 3".replace(/\d/g, parseInt) 答案:"1NaN3"解析:replace()回调函数的四个参数:1、匹配项2、与模式中的子表达式匹配的字符串3、出现的位置4、stringObject 本身。如果没有与子表达式匹配的项,第二参数为出现的位置.所以第一个参数是匹配项,第二个参数是位置parseInt('1',0)parseInt('2',2)//2进制中不可能有2parseInt('3',4)巩固:"Andthe%1".replace(/%([1-8])/g,function(match,a,b,d){console.log(match+""+a+""+b+""+d)});//%118Andthe%1 33. 这段代码的执行结果? functionf(){}varparent=Object.getPrototypeOf(f);f.name//?parent.name//?typeofeval(f.name)//?typeofeval(parent.name)//? 这段代码的执行结果? 答案:"f","Empty","function",error解析:f的函数名就是fparent是f原型对象的名字为"",先计算eval(f.name)为f,f的数据类型是functioneval(parent.name)为undefined,"undefined" 34. 这段代码的执行结果? varlowerCaseOnly=/^[a-z]+$/;lowerCaseOnly.test(null),lowerCaseOnly.test()] 这段代码的执行结果? 答案:[true,true]解析:这里 test 函数会将参数转为字符串. 'nul','undefined'自然都是全小写了 35.[,,,].join(",") 答案:",,"解析:因为javascript 在定义数组的时候允许最后一个元素后跟一个,所以这个数组长度是3,巩固:[,,1,].join(".").length//3 36. 这段代码的执行结果? vara={class:"Animal",name:'Fido'};a.class 这段代码的执行结果? 答案:other解析:这取决于浏览器。类是一个保留字,但是它被Chrome、Firefox和Opera接受为属性名。在另一方面,每个人都会接受大多数其他保留词(int,私有,抛出等)作为变量名,而类是VordBoint。 37.var a = new Date("epoch") 答案:other解析:您得到“无效日期”,这是一个实际的日期对象(一个日期的日期为true)。但无效。这是因为时间内部保持为一个数字,在这种情况下,它是NA。在chrome上是undefined正确的是格式是vard=newDate(year,month,day,hours,minutes,seconds,milliseconds); 38. ["1", "2", "3"].map(parseInt) 答案:[1,NaN,NaN]解析:parseInt(val, radix):两个参数,val值,radix基数(就是多少进制转换)map能传进回调函数3参数(element,index,array)parseInt('1',0);//0代表10进制parseInt('2',1);//没有1进制,不合法parseInt('3',2);//2进制根本不会有3巩固:["1","1","11","5"].map(parseInt)//[1,NaN,3,NaN]parseInt('13',2)//1,计算机在二进制只认识0,1,parseInt转换时就当作不认识的字符忽略了parseInt('18str')//1810进制能认识到9parseInt(1/0,19)//181/0==Infinity19进制计算机能认识最后一个字符是i详细解析在下面的链接 39. 这段代码的执行结果? vara=Date(0);varb=newDate(0);varc=newDate();[a===b,b===c,a===c] 这段代码的执行结果? 答案:[false,false,false]解析:当日期被作为构造函数调用时,它返回一个相对于划时代的对象(JAN 011970)。当参数丢失时,它返回当前日期。当它作为函数调用时,它返回当前时间的字符串表示形式。a是字符串a===b//数据类型都不同,肯定是falseb是对象b===c//引用类型,比的是引用地址c也是对象a===c//数据类型都不同,肯定是false巩固:vara=Date(2018);varb=Date(2001);[a===b]//[true]Date()方法获得当日的日期,作为函数调用不需要,返回的同一个字符串"TueJun12201814:36:24GMT+0800(CST)"当然如果a,b执行时间相差1秒则为false 40. 这段代码的执行结果? varmin=Math.min(),max=Math.max()min<max 这段代码的执行结果? 答案:false解析:Math.min不传参数返回Infinity,Math.max不传参数返回-Infinity,Infinity应该大于-Infinity,所以是false巩固:Number.MAX_VALUE>Number.MIN_VALUE//true 41. 这段代码的执行结果? functioncaptureOne(re,str){varmatch=re.exec(str);returnmatch&&match[1];}varnumRe=/num=(\d+)/ig,wordRe=/word=(\w+)/i,a1=captureOne(numRe,"num=1"),a2=captureOne(wordRe,"word=1"),a3=captureOne(numRe,"NUM=2"),a4=captureOne(wordRe,"WORD=2");[a1===a2,a3===a4] 这段代码的执行结果? 答案:[true,false]解析:/g有一个属性叫lastIndex,每次匹配如果没有匹配到,它将重置为0,如果匹配到了,他将记录匹配的位置。我们看一个简单的例子吧。varnumRe=/num=(\d)/g;numRe.test("num=1abcwewe")//truenumRe.lastIndex//5匹配到num=1后在5的索引位置numRe.exec("num=1")//fales这次要从5的索引位置,开始匹配numRe.lastIndex//0上一次匹配失败了numRe.lastIndex重制为0 42. 这段代码的执行结果? vara=newDate("2014-03-19"),b=newDate(2014,03,19);[a.getDay()===b.getDay(),a.getMonth()===b.getMonth()] 这段代码的执行结果? 答案:[false,false]解析:vara=newDate("2014-03-19")//能够识别这样的字符串,返回想要的日期WedMar19201408:00:00GMT+0800(CST)b=newDate(2014,03,19);//参数要按照索引来SatApr19201400:00:00GMT+0800(CST)月是从0索引,日期是从1getDay()是获取星期几getMonth()是获取月份所以都不同巩固:[a.getDate()=== b.getDate()]//true 43. 这段代码的执行结果? if('http://giftwrapped.com/picture.jpg'.match('.gif')){'agiffile'}else{'notagiffile'} 这段代码的执行结果? 答案:'agiffile'解析:String.prototype.match接受一个正则,如果不是,按照newRegExp(obj)转化. 所以 . 并不会转义。那么/gif 就匹配了/.gif/巩固:if('http://giftwrapped.com/picture.jpg'.indexOf('.gif')){'agiffile'}else{'notagiffile'}//indexOf如果匹配不到返回是-1所以是'agiffile' 44.这段代码的执行结果? functionfoo(a){vara;returna;}functionbar(a){vara='bye';returna;}[foo('hello'),bar('hello')] 这段代码的执行结果? 答案:["hello","bye"]解析:最后一题很简单吧,变量声明 本文分享自微信公众号 - JavaScript忍者秘籍(js-obok)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

深度观察 | Akamai专家解读爬虫攻击现状与趋势

即将开播:4月29日,民生银行郭庆谈商业银行金融科技赋能的探索与实践 【51CTO.com原创稿件】近日,51CTO记者采访了Akamai中国区企业事业部总经理何铭及Akamai大中华区产品市场经理刘炅,就恶意爬虫攻击演进、危害以及如何防御等话题进行了深入交流。 什么是爬虫? 首先,我们来解读下,什么是爬虫(BOT)?BOT,意为搜索引擎抓取机器人,也称爬虫。互联网中的数据是海量的,如何自动高效地获取互联网中我们感兴趣的信息并为我们所用是一个重要的问题,而爬虫技术就是为了解决这些问题而生的。 “其实,在互联网流量中,有40%的流量是爬虫的流量。当然,爬虫有好有坏,善意的爬虫主要用于网络索引、内容聚合以及提取市场或价格信息。而恶意的爬虫由恶意攻击者操纵,用于针对所有行业、地区和渠道的Web内容搜刮、交易欺诈、垃圾邮件以及DDoS和撞库攻击。针对这些爬虫,企业机构需要进行识别和管理,进行有效防范。”刘炅说道。 恶意爬虫是一种自动化的恶意软件,通过远程互联网对目标站点进行攻击,以达到商业欺诈的目的。常见的攻击方式有凭证滥用、账户滥用、银行卡攻击、库存囤积、薅羊毛。凭证滥用类攻击是撞库攻击最主要的方式,它将从黑市上获取的大量用户数据和账户信息在不同的网站进行登录尝试,从而得到有效账户,最终把这些账户非法贩卖给其他人。账户接管或称为账户盗用是另一种撞库攻击的常见类型,指对包括电商、游戏账户在内的互联网账户的盗取。这种攻击通常也是通过登陆尝试或蛮力手段得到账户,在接管账户后进行信息窃取或进一步攻击。 Akamai大中华区产品市场经理刘炅 爬虫攻击的演进历程 回顾爬虫攻击的演进历程,刘炅将其划分为四个阶段: 最开始,爬虫比较简单,都是通过单IP或者是极少的IP搭建一个恶意攻击点。此外,针对客户端攻击的恶意软件也比较简单,均是采用命令行的攻击方式。在这个阶段,外部浏览器还没有Cookie值,也没有添加Script的可执行脚本。所以防护这些爬虫比较简单,企业在找到攻击源后实施访问控制(采取黑名单限制等手段),就可以进行防护。 第二阶段,随着浏览器引入Cookie功能和具备Script脚本执行能力,爬虫采用简易浏览器实施攻击,因而此前简单的防护方式已经无法识别爬虫。相应地,防护手段需要加入对Script值的验证等能力(包括JS变量的验证)来探测攻击端浏览器的真假。 第三阶段,此时的爬虫攻击基于真实浏览器,并开始模拟人的行为,因此企业需要更进一层的检测方式。比如,Akamai的Bot Manager Premier(爬虫管理器)产品可以通过键盘敲击、鼠标滑动等操作来有效识别爬虫流量。 第四阶段,也是现在所处阶段的特点是爬虫攻击点呈现分布式、且可利用更多的僵尸网络发起攻击,从而导致企业对爬虫流量的判断更加困难。其次,爬虫也在模拟更多的真实人类行为,因此对爬虫的攻击检测和防护模式需要采用机器学习等技术加以识别。 Akamai中国区企业事业部总经理何铭 “三年前,我发现大部分中国客户对爬虫没有特别的概念,且对爬虫危害的认识较浅。但从2018年开始,Akamai的中国客户基本上都采取了多种反爬虫手段。由此可见,国内企业对爬虫危害的认识提升很快。”何铭也回忆并举例说,“很多年轻人喜欢购买限量款鞋子,因此品牌网站需要通过摇号排队的方式才能售卖。但是黑客可以使用爬虫来瞬间预定所有限量款鞋子,从而转售盈利。类似的案例还有很多,侵占、抢占库存,甚至发动DDoS攻击堵塞网络,而很多小网站是经受不住这种打击的。所以,从2018年开始,各个行业对爬虫管理越发重视。” 同时,何铭也注意到了另外一个现象:在对恶意爬虫管理更加重视的同时,很多网站开始引入善意爬虫,通过内嵌搜索引擎来促进物品销售。“这也是现在爬虫管理市场值得注意的方向。我们需要阻止恶意爬虫、放行善意爬虫,一刀切地阻止所有爬虫会影响企业商品销量和业务。” 爬虫攻击次数居高不下,手段日益复杂 谈及近年来爬虫攻击的趋势,刘炅告诉记者,凭借每日交付超过50 Tbps的Web流量,Akamai对互联网上的攻击流量有着极大的可视性,特别是对于爬虫攻击趋势的研究。据Akamai今年二月发布的《2020年互联网安全状况报告:金融服务——恶意接管尝试》,爬虫攻击呈现出以下趋势: 第一,攻击次数居高不下。在报告统计的约两年内,Akamai共发现了超过850亿次攻击,日均攻击量达到1.2亿次之多。 第二,攻击手段越发复杂。攻击者会通过多合一的工具、利用僵尸网络发起分布式攻击。鉴于当前API协议的广泛使用,攻击者便利用API的自动化特性、采用API作为主要攻击手段。Akamai发现近20%的凭证滥用攻击都是基于API的登录方式。 第三,金融业已成为攻击重灾区。根据Akamai的数据,在针对金融服务业发起的撞库攻击中,高达75%的攻击直接以API为目标。 何铭表示:“其实各行各业都会受到爬虫攻击,零售业是受到爬虫攻击最为严重的行业之一,除此之外,爬虫攻击的主要目标还包括媒体、金融、酒店及旅游业。在零售业中,服装类、电商门户类以及百货类的网站更易遭到爬虫攻击。” Akamai和Ponemon Institute的联合研究显示,由爬虫引起的“撞库”攻击每年会给企业带来高达270万美元的损失。爬虫攻击给企业造成的损失可见一斑。 抵御爬虫攻击,Akamai一直在行动 那么,究竟该如何应对爬虫攻击?何铭认为:“对于爬虫的管理,企业首先要做的是甄别,包括规则和策略的制定。”以电商行业为例,电商网站构建起来较为复杂,一方面需要第三方爬虫的支持来实现引流、实现让用户能够访问库存,保证在库存充足的前提下销售产品。同时,也要防范竞争对手恶意爬取其库存信息,抢走库存而影响对外销售。因此,企业IT团队既要识别恶意爬虫、进行阻挡,又要甄别出善意爬虫、予以放行,还要做好DDoS攻击等防护工作。 随着爬虫攻击方式的演进,Akamai爬虫管理产品和解决方案也在不断升级迭代。就在三月,Akamai对爬虫管理产品进行了升级,全面提升攻防能力。具体而言,实现了更多更精准的爬虫检测方法,加入了POW(Proof of Work)挑战检测方法;基于人工智能的威胁评分机制,根据分值可实施部署灵活的防护策略;增加更多场景支持,尤其对于跨域场景的支持,为了使跨域请求的检测更加精准,Akamai定义了新的攻击检测方式,从而扩展更多的应用防护场景;另外实现了与真实用户监控(RUM)页面性能检测产品集成,分析和判断爬虫对业务性能的影响,并进行可视化管理。 今年二月,Forrester发布了“Forrester New Wave™:2020年第一季度爬虫程序管理评估”报告,并认定Akamai为“领导者”。显然,这是对Akamai爬虫管理能力的充分肯定。目前,无论是从产品功能特性还是市场占有率上,Akamai在爬虫管理界都处于前列。从最初单一的IP攻击到模拟浏览器和人类行为,爬虫的攻击方式不停变化。鉴于此,Akamai针对爬虫的检测方案也是多种多样,包括IP拦截、速率控制、Cookie和Java参数检测以及用户行为的深度分析。而对于爬虫的缓解方案,除了最基本的监控和拦截,Akamai还会进行限速、延缓和疏导。 “有的企业希望一、两天就能实现对爬虫的管理,这是不现实的。但爬虫管理解决方案部署过程的快慢,仰仗于安全厂商在业内的技术沉淀和经验积累。高效的爬虫管理需要长期积累的经验和能力。一旦客户选择了Akamai,我们就可以立即开启甄别模式、预警模式,快速进入策略的制定和防护的开启,这也是Akamai引以为豪之处。”何铭表示,据某电商客户反馈,在部署Akamai爬虫管理解决方案一段时间后,他们发现自己网站的大部分流量都是爬虫流量,而以前他们对此根本没有感知。此外,他们在部署Akamai方案前对爬虫攻击流量的发现率大概为10%,但部署后的识别率达到约99%。 综上可以看出,由于与生俱来的边缘属性和优势,Akamai的爬虫管理解决方案可以很好地应用于多种环境,包括用户本地的数据中心和多云环境中的防护场景。Akamai的爬虫防护方案并非一个单点方案,而是一个分层次的、全栈的防护方案,即从DDoS和网页防护到爬虫管理乃至API攻击都可进行防护。基于边缘的安全能力,Akamai提供了一整套防护解决方案来帮助企业抵御目前最复杂的网络攻击。 【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】 【责任编辑: 蓝雨泪 TEL:(010)68476606】

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册