跨站请求伪造
英文全称Cross Site Request Forgery(CSRF),是一种冒充受信任用户,向服务器发送非预期的请求。例如可能在某个有权限访问的URL后加入恶意的参数实行攻击。
跨站脚本攻击主要的攻击手段是在网站注入恶意的客户端代码,获取到当前网站的用户私密信息从而进行攻击。而跨站请求伪造则是冒充已经受信任的用户来实现目的,方式略有不同。
一般通过以下方式来防御:
请求来源检查
检查请求来源是通过HTTP请求的头字段来实现:Referer和Origin。这两个字段不允许JavaScript对字段的值进行修改。
Origin只有在POST请求中才发送,和Referer不同的是,它也可以在HTTPS请求中存在。
如果在请求字段中都存在,那都需要校验,确定了请求的源头,那CSRF风险会大幅降低。
Origin: https://www.example.com:80
Referer: https://www.example.com:80
有时候会被问到GET和POST请求有什么区别?GET请求主要是获取资源,不会对资源进行修改;而POST请求会;当然你不按照标准,要用GET请求来修改资源,那也是可以实现的,只是存在一定的风险,像请求来源检查预防CSRF的字段只会在POST请求中。
使用CSRF令牌
在每一个会话中,服务器会发送一个令牌给客户端,当客户端请求服务端的时候,会通过表单或Ajax请求回传给服务器,服务器会检查令牌的真实性,是否过期,还有是否被篡改过,如果发生了类似情况,则令牌就会失效,请求则认为是不安全的。
只要CSRF令牌不能被伪造,并且在客户端发送给服务端的时候是安全的,那就可以大大降低CSRF的攻击。
跨站脚本攻击
英文全称Cross-site-scripting。
根据开放式Web应用项目,XSS在2017年被认为是7种最常见的Web应用程序漏洞之一。
这种攻击的主要表现是攻击者在网站注入恶意的客户端代码,以此来突破网站限制,冒充被攻击者来实现自己的目的。
所以,为了防止跨站脚本攻击,我们大体可以从两个方面来预防:
- 尽量不写那种会被攻击者利用的程序代码
- 需要对执行的内容进行校验、净化
尽量避免的API
DOMParser API,它可以将parseFromString方法中的字符串内容加载到DOM节点上,相对于从服务器端加载结构化的DOM,这个方法是比较方便的,但有很严重的安全隐患。而通过document.createElement()和document.appendChild()创建的DOM节点,则安全得多,虽然用起来可能更麻烦一点。
在SSR过程中,需要将标签属性值都拼装成字符串返回,例如:
value === '' ? ` ${key}` : ` ${key}="${escapeHtml(value)}"`
使用escapeHtml函数来转义也可以防止XSS攻击。
以下是一个在JavaScript中实现的escapeHtml函数实例:
function escapeHtml(str) {
// 包含了字符到对应HTML实体的映射关系
let escapeMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/'
}
return str.replace(/[&<>"'/]/g, function(char) {
return escapeMap[char];
})
}
内容安全策略(CSP)
是一个安全配置工具。
允许我们以白名单的形式列出可以动态加载脚本的网站。并且默认情况下,CSP可以禁止任何内联脚本的执行,这样就很有效的防止了第三方攻击者注入的脚本执行。但需要注意的是,使用CSP的情况下,不要使用eval()函数,因为eval的传参是字符串,如果字符串内是可执行表达式的话,也会正常被执行。
<meta http-equiv="Content-Security-Policy" content="script-src https://www.example.com;">
字符串净化
字符串或类字符串虽然本身不是DOM结构,但有可能被解析成DOM节点。例如:
'<p>跨站脚本攻击XSS</p>'
这是个字符串,但如果赋值给innerHTML,则就是DOM节点了,而innerText就会做净化处理。
CSS净化
CSS净化主要指的是净化HTTP相关的CSS属性,或者只允许用户修改指定的CSS字段。