题目概览
- HTML与XHTML二者有不同
- 写出主流浏览器内核私有属性的css前缀
- 手写一个幻灯片的效果
- 对XSS和CSRF的理解
题目解答
HTML与XHTML二者有不同
XHTML 元素必须被正确地嵌套
在 HTML 中,某些元素可以像这样彼此不正确地嵌套
This text is bold and italic
在 XHTML 中,所有的元素必须像这样彼此正确地嵌套
This text is bold and italic
- Coffee
- Tea
- Black tea
- Green tea
- Milk
XHTML 元素必须被关闭
非空标签必须使用结束标签
This is a paragraph
This is another paragraph
空标签也必须被关闭,空标签也必须使用结束标签,或者其开始标签必须使用/>结尾
A break:
A horizontal rule:
An image:
标签名必须用小写字母:XHTML 规范定义标签名和属性对大小写敏感
This is a paragraph
XHTML 文档必须拥有根元素:所有的 XHTML 元素必须被嵌套于
根元素中。其余所有的元素均可有子元素。子元素必须是成对的且被嵌套在其父元素之中
... ...
写出主流浏览器内核私有属性的css前缀
- Chrome:Blink内核
-webkit-
- Safari:WebKit内核
-webkit-
- Firefox :Gecko内核
-moz-
- IE:Trident内核
-ms-
- Opera:Presto内核
-o-
手写一个幻灯片的效果
.huanDengPic {
width: 237px;
height: 160px;
margin: 50px auto 0;
overflow: hidden;
box-shadow: 0 0 5px rgba(0,0,0,1);
background-size: contain;
animation: loops 10s infinite;
}
@keyframes loops {
0% {background:url(https://github.com/AnsonZnl/images/blob/master/Unclassified/WechatIMG1.jpeg?raw=true) no-repeat;
}
50% {
background:url(https://github.com/AnsonZnl/images/blob/master/Unclassified/WechatIMG2.jpeg?raw=true) no-repeat;
}
100% {
background:url(https://github.com/AnsonZnl/images/blob/master/Unclassified/WechatIMG3.jpeg?raw=true) no-repeat;
}
}
对XSS和CSRF的理解
XSS
含义:跨站脚本攻击(Cross Site Scripting),为了不和层叠样式表 CSS 混淆,故将跨站脚本攻击缩写为 XSS)。恶意攻击者往 Web 页面里插入恶意 Script 代码,当用户浏览该页之时,嵌入其中 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的
分类:
- Reflected XSS(基于反射的 XSS攻击):是指xss代码在请求的url中,而后提交到服务器,服务器解析后,XSS代码随着响应内容一起传给客户端进行解析执行。(直接反射显示在页面)
- Stored XSS(基于存储的 XSS攻击):Stored XSS和 Reflected XSS的差别就在于,具有攻击性的脚本被保存到了服务器端(数据库,内存,文件系统)并且可以被普通用户完整的从服务的取得并执行,从而获得了在网络上传播的能力
- DOM-based or local XSS(基于DOM或本地的 XSS 攻击):DOM型 XSS其实是一种特殊类型的反射型 XSS,它是基于 DOM文档对象模型的一种漏洞。可以通过 DOM来动态修改页面内容,从客户端获取 DOM中的数据并在本地执行。基于这个特性,就可以利用 JS脚本来实现 XSS漏洞的利用
触发:
- 在网页 input 或者 textarea 中输入
或者其他脚本
- 直接使用 URL 参数攻击
https://www.baidu.com?jarttoTest=
- 在网页 input 或者 textarea 中输入
XSS防御
输入过滤,避免 XSS 的方法之一主要是将用户输入的内容进行过滤。对所有用户提交内容进行可靠的输入验证,包括对 URL、查询关键字、POST数据等,仅接受指定长度范围内、采用适当格式、采用所预期的字符的内容提交,对其他的一律过滤。(客户端和服务器都要)
输出转义
往 HTML 标签之间插入不可信数据的时候,首先要做的就是对不可信数据进行 HTML Entity 编码 HTML 字符实体
function htmlEncodeByRegExp (str){ var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g,"&"); s = s.replace(//g,">"); s = s.replace(/ /g," "); s = s.replace(/\'/g,"'"); s = s.replace(/\"/g,"""); return s; } var tmpStr="
123
"; var html=htmlEncodeByRegExp (tmpStr) console.log(html) //<p>123</p> document.querySelector(".content").innerHTML=html; //123
将用户数据输出到html 标签的属性时,必须经过标签属性的转义。注意:不包含href, src, style和事件处理函数属性(比如onmouseover)。除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 HH; (以开头,HH则是指该字符对应的十六进制数字,分号作为结束符)
content//数据不在引号内content//数据在单引号内content//数据在双引号内对动态生成的JavaScript代码,这包括脚本部分以及HTML标签的事件处理属性(Event Handler,如onmouseover, onload)等进行Javascript编码。使用“”对特殊字符进行转义,除数字字母之外,小于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; }
将不可信数据插入到HTML URL里时,对这些数据进行URL编码。除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 %HH (以 % 开头,HH则是指该字符对应的十六进制数字)
对URI使用encodeURI() 对参数使用encodeURIComponent()
使用 HttpOnly Cookie:将重要的cookie标记为httponly,这样的话当浏览器向Web服务器发起请求的时就会带上cookie字段,但是在js脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie。现代web开发框架如vue.js、react.js等,在设计的时候就考虑了XSS攻击对html插值进行了更进一步的抽象、过滤和转义,我们只要熟练正确地使用他们,就可以在大部分情况下避免XSS攻击
CSRF
含义:CSRF 的全称是“跨站请求伪造”,而 XSS 的全称是“跨站脚本”。看起来有点相似,它们都是属于跨站攻击——不攻击服务器端而攻击正常访问网站的用户,但它们的攻击类型是不同维度上的分 类。CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求
触发:
http://www.mybank.com/Transfer.php?toBankId=11&money=1000
防御
- 验证 HTTP Referer 字段,利用 HTTP 头中的 Referer 判断请求来源是否合法,Referer记录了该 HTTP 请求的来源地址。优点是简单易行,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。 缺点是Referer 的值是由浏览器提供的,不可全信,低版本浏览器下 Referer 存在伪造风险。用户自己可以设置浏览器使其在发送请求时不再提供 Referer 时,网站将拒绝合法用户的访问
- 在请求地址中添加 token 并验证。CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。通常使用的方法就是在每次页面加载时,使用 javascript 遍历整个 dom 树,对于 dom 中所有的 a 和 form 标签后加入 token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的 html 代码,这种方法就没有作用,还需要程序员在编码时手动添加 token。优点是这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对。缺点是对所有请求都添加 token 比较困难。难以保证 token 本身的安全,依然会被利用获取到 token。
- 在 HTTP 头中自定义属性并验证。这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。优点是统一管理 token 输入输出,可以保证 token 的安全性。缺点是有局限性,无法在非异步的请求上实施。