随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,在移动互联网时代,web除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。当然,浏览器自身也在不断在进化和发展,不断引入 CSP、Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要技术人员不断进行“查漏补缺”。
近几年,我们面临很多安全挑战,也积累了大量的实践经验。我们梳理了常见的XSS安全问题以及对应的解决方案,希望可以帮助技术人员在日常开发中不断预防和修复安全漏洞。
一. 为什么会有 xss 攻击
因为前端输入的不可信,就会导致恶意代码在浏览器中执行。
1. 通过一个异常的输入,在用户的浏览器中插入恶意的 javascript 脚本。
2. 直接添加一个有恶意脚本的网页,诱导用户打开。
3. 将恶意脚本以话题的方式提交到论坛中,诱使网站管理员打开这个话题,从而获得管理员权限,控制整个网站。
二. xss 攻击的种类
1. 存储型 XSS - 存储在数据库中
-
攻击者将恶意代码提交到目标网站的数据库中。
-
用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
-
用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
-
恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等
存储型 xss 案例:
-
在UGC(User-generated Content,用户生产内容,百度贴吧,微博等)业务上,比较容易出现存储型 xss 漏洞。
如何解决:
-
属性值过滤
-
重写
参考:腾讯安全应急响应中心:https://security.tencent.com/index.php/blog/msg/53
2. 反射型 XSS
-
攻击者构造出特殊的 URL,其中包含恶意代码。
-
用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
-
用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
-
恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等
反射型 xss案例:
-
script 标签出现在 url
-
jacascript:代码出现在url
-
jAvascRipt: 代码出现在url
解决:白名单解决法,在白名单内就返回页面,不再一律返回404
某天,公司做需要一个搜索页面,根据 URL 参数决定关键词的内容。代码如下:
<input type="text" value="<%= getParameter("keyword") %>">
<button> 搜索 </button>
<div>
您搜索的关键字是:<%= getParameter("keyword") %>
<div>
如果 黑客构造一下的url, 就可以轻易发起攻击。
http://xxx/search?keyword="><script>alert('XSS');</script>
当浏览器请求 http://xxx/search?keyword="><script>alert('XSS');</script>
时,服务端会解析出请求参数keyword
,得到"><script>alert('XSS');</script>
,拼接到 HTML 中返回给浏览器。形成了如下的 HTML:
<input type="text" value=""><script>alert('XSS');</script>">
<button>搜索</button>
<div>
您搜索的关键词是:"><script>alert('XSS');</script>
</div>
问题的原因是,浏览器把用户的输入当成了脚本进行了执行。
解决办法:只要告诉浏览器这段内容是文本就可以解决了
于是有了下面这段代码:
<input type="text" value="<%= escapeHTML(getParameter("keyword")) %>" >
<button>搜索</button>
<div>
您搜索的关键词是: <%= escapeHTML(getParameter("keyword")) %>
</div>
escapeHTML()
按照如下规则进行转义:
转义之后确实可以解决上面的那个利用标签闭合,进行攻击的情况。但是新的问题继续有:
如果 url 是这样的形式:http://xxx/?redirect_to=javascript:alert('XSS')
, 展示在页面的一个 a 标签上:
<a href="javascript:alert('XSS')">跳转...</a>
点击 a 标签,还是会弹出 xss,原来不仅仅是特殊字符,连javascript:
这样的字符串如果出现在特定的位置也会引发 XSS 攻击。
考虑到只要 URL 的开头不是javascript:
, 是不是就可以解决上面的问题。
代码如下:
// 禁止 URL 以 "javascript:" 开头
xss = getParameter("redirect_to").startsWith('javascript:');
if (!xss) {
<a href="<%= escapeHTML(getParameter("redirect_to"))%>">
跳转...
</a>
} else {
<a href="/404">
跳转...
</a>
}
这样就安全了吗?不是的。
如果 url 的链接是这样的 :http://xxx/?redirect_to=jAvascRipt:alert('XSS')
,或 http://xxx/?redirect_to=%20javascript:alert('XSS')
依旧可以完成 xss 攻击。
那么如何解决呢?可以通过白名单的方法。
代码如下:
// 根据项目情况进行过滤,禁止掉 "javascript:" 链接、非法 scheme 等
allowSchemes = ["http", "https"];
valid = isValid(getParameter("redirect_to"), allowSchemes);
if (valid) {
<a href="<%= escapeHTML(getParameter("redirect_to"))%>">
跳转...
</a>
} else {
<a href="/404">
跳转...
</a>
}
总结:
-
攻击者利用用户输入片段,拼接特殊格式的字符串,突破原有位置的限制,形成了代码片段。
-
通过 HTML 转义,可以防止部分 XSS 攻击。(不同情况下,需要采用不同的转义规则)
-
如果数据是以 json 的形式,内联到 html 中 , 插入 json 的地方不能用 escapeHTML() 转义, 这样会破坏json格式。
-
如果 json 中包含字符串
</script>
时, 会闭合前一个<script>
标签,通过增加一个<script>
标签,就可以完成注入。 -
对于链接跳转,如
<a href="xxx"
或location.href="xxx"
,要检验其内容,禁止以javascript:
开头的链接,和其他非法的 scheme。
3. 基于 DOM 的 XSS(其实是一种特殊类型的反射型 xss)
1. 攻击者构造出特殊的 URL,其中包含恶意代码。
2. 用户打开带有恶意代码的 URL。
3. 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。
dom 型 xss 案例
-
取值写入页面或动态执行
想要在客户端实现接受参数并写入页面或动态执行,就不得不用到JavaScript“三姐妹”,她们分别是:innerHTML、document.write、eval。
-
直接从URL的锚参数(即位于#后面的参数)中取值,不经过任何处理直接innerHTML写入页面, 如果攻击者构造这样的 url :
http://xxx.com/xxx.htm#msg=<img /src=x one rror=alter(1)/>
由于整个攻击不需要像服务端发送任何数据,所以即使业务接入了 web 应用防火墙(WAF),也无法抓到这类 dom xss。
-
从 cookie中取值
直接从cookie中取值写入页面或动态执行,原理基本同从URL中的取参数值写入页面或动态执行,只是换了一个取值来源而已。
但同时我们注意到,还有一种较为特殊的业务场景,取cookie键值,动态拼接要页面引入前端资源的URL。
代码如下:
-
如果window.isp取到的值为“www.attacker.com/”
,最终拼接出来的静态资源URL路径为:http://www.attacker.com/victim.com
,因为“.”和“/”都不在转义范围内,导致攻击者可以向页面引入自己站点下的恶意js文件,进而实施DOM-XSS攻击.
-
从localStorage、Referer、Window name、SessionStorage中的取参数值写入页面或动态执行
一般情况下 window.name 容易被认为来源可信,但借助 iframe 的 name 属性,攻击者可以将页面的 window.name 设置为攻击代码,构造DOM XSS:
总结:
1. 在取值写入页面或动态执行的业务场景下,在将各种来源获取到的参数值传入JavaScript“三姐妹”函数(innerHTML、document.write、eval)处理前,对传入数据中的HTML特殊字符进行转义处理能防止大部分DOM-XSS的产生.
2. 根据不同业务的真实情况,还应使用正则表达式,针对传入的数据做更严格的过滤限制,才能保证万无一失。
3. 不到万不得已,不要使用eval函数处理不可控的外部数据。
4. 对于从cookie,还是从localStorage、Referer、Window name、SessionStorage中获取数据,都应使用安全的函数,对传入的数据做过滤后,再传递给相关函数写入页面或执行。
5. 参考/使用filter.js库
2. 前端实现页面跳转
最常用的方式有 location.href 、location.replace() 、 location.assign()
也许提到页面跳转业务场景下的安全问题,你首先会想到限制不严导致任意URL跳转,而DOM XSS与此似乎“八竿子打不着”。但有一种神奇的东西叫“伪协议”,比如:“javascript:”、“vbscript:”、“data:”、“tencent:”、“mobileqqapi:”等,其中“javascript:”、“vbscript:”、“data:”在浏览器下可以执行脚本:
使用这些伪协议执行的JavaScript代码,就相当于在页面内注入了一段恶意代码
-
使用indexOf判断URL参数是否合法, 代码如下
indexOf 是一个从头到尾检索字符串,查找是否有字串 xxx,如果攻击者构造 'javascript:alert(1);//xxx://' 这样的url,即可以成功让 indexOf 返回true,并进入跳转逻辑,完成攻击。又可以让 javascript 代码运行时忽略。(因为 xxx:// 位于JavaScript代码的注释部分)
-
正则表达式缺陷
由于 indexOf下藏着的深坑,想出用正则表达式解决这类问题,但是正则表达式也会有一些问题,比如:
跳转页面只能是qq.com/paipai.com
。认为这样就可以解决DOM-XSS和URL跳转的问题,但忘了一个神奇的符号“^”,加上和不加上,过滤的效果具有天壤之别。
(因为正则没有严格限制传入的URL开头只能是“http”或“https”,攻击者仍然可以构造“javascript:alert(1);//http://www.qq.com”来绕过看似严格的过滤。)
总结:
-
限制能够跳转页面的协议:只能是http、https或是其他指可控协议;
-
严格限制跳转的范围,如果业务只要跳转到指定的几个页面,可以直接从数组中取值判断是否这几个页面。
-
如果跳转范围稍大,正确使用正则表达式将跳转URL严格限制到可控范围内。
三、XSS 攻击的总结
-
防范存储型和反射型 XSS 是后端的责任
-
DOM 型 XSS 攻击不发生在后端,是前端的责任。
-
不同的上下文,调用不同的转义规则
如 HTML 属性、HTML 文字内容、HTML 注释、跳转链接、内联 JavaScript 字符串、内联 CSS 样式表等,所需要的转义规则不一致。业务 需要选取合适的转义库,并针对不同的上下文调用不同的转义规则。
四. xss 攻击有什么危害
窃取敏感信息:攻击者可以通过注入恶意脚本,窃取用户的敏感信息,如用户名、密码、Cookie等。这些信息可以用来冒充用户身份进行恶意操作。
劫持会话:攻击者通过窃取用户的会话令牌或Cookie,能够劫持用户的会话,实施未经授权的操作,如修改账户信息、发表言论等。
篡改网页内容:攻击者可以通过注入恶意脚本,修改网页上的内容,向用户展示虚假信息、欺骗性的广告、恶意链接等,影响用户的体验和信任。
钓鱼攻击:攻击者可以伪造合法网站,诱使用户输入敏感信息,如银行账户密码、信用卡信息等,从而实施钓鱼攻击。
恶意操作:攻击者可以在用户浏览器中执行恶意脚本,例如发起DDoS攻击、改变用户设置、执行未授权操作等,从而对用户和网站造成实际损害。
信任破坏:如果用户发现网站存在XSS漏洞,可能会对该网站产生质疑并失去信任,导致用户流失。
传播恶意代码:攻击者可以利用XSS漏洞传播恶意软件、病毒或恶意脚本,进一步扩大攻击范围。
破坏隐私:用户的隐私可能会被泄露,从而导致个人、财务等方面的损失。
五、防止 XSS 攻击
为了有效防御跨站脚本攻击,以下是一些常见的防御措施:
输入验证和过滤:对于所有用户输入的数据,包括表单提交、URL参数等,进行严格的验证和过滤。确保只允许合法和预期的输入通过。可以使用白名单过滤、正则表达式匹配等方法来防止不安全的输入。
输出转义:在将用户输入数据插入到HTML页面时,使用适当的输出转义机制,将特殊字符转换为它们的HTML实体形式。这样可以防止浏览器将输入内容解释为代码。
使用安全的编码库:使用安全的编码库来处理用户输入和输出,这些库会自动执行必要的输入验证、过滤和输出转义,从而减少开发者的出错机会。
Content Security Policy(CSP):CSP是一种安全策略,可以在HTTP头中设置,用于限制页面可以加载的资源和执行的脚本。通过设置合适的CSP规则,可以有效减少XSS攻击的风险。
HttpOnly和Secure标记:在设置Cookie时,使用HttpOnly标记确保Cookie不能被JavaScript访问,使用Secure标记确保Cookie只在HTTPS连接中传输。
使用框架和库:使用流行的Web开发框架和库(如React、Angular、Vue.js等),这些框架通常有内置的安全机制,可以减少XSS攻击的风险。
教育用户:提高用户的网络安全意识,让他们了解XSS攻击的风险和如何避免受到攻击。
定期安全审计:定期检查和审计代码,查找潜在的XSS漏洞,及时修复。
最小化权限:在数据库和服务器上使用最小权限原则,限制应用程序和用户的访问权限,减少攻击者能够获取的敏感信息。
避免内联脚本:尽量避免使用内联脚本,而是使用外部JavaScript文件。这样可以帮助隔离用户输入和执行的代码。
使用HTTPOnly Cookie:使用HTTPOnly Cookie可以防止通过JavaScript访问Cookie,从而减少攻击者窃取会话令牌的可能性。
安全开发实践:遵循安全的开发实践,编写安全的代码,不信任用户输入,使用最新的漏洞库和工具进行代码审查和漏洞扫描。
标签:XSS,危害,URL,恶意代码,用户,收藏,跳转,攻击者 From: https://blog.csdn.net/weixin_45840241/article/details/139431267