产生原因:网页程序代码没有对用户输入进行特定过滤导致用户可以输入一些恶意js代码被程序执行
XSS漏洞主要分为三种,反射型XSS、dom型XSS、存储型XSS
一、反射型XSS
用户输入的恶意js经过服务器处理后立即反射回页面并执行 ,攻击过程具有一次性、非持久性的特点。
常用的反射型XSS漏洞所用的标签有<img>、<svg>、<a>等


当然程序设计时会对这些某些特定的输入进行过滤比如说javascript这样的关键字。但是这样的过滤也是可以绕过的通常会用到HTML实体编码、url编码、JavaScript Unicode编码。
这里的编码优先级是HTML实体编码>url编码>JavaScript Unicode
所以当错误的使用编码可能会导致"<"被编码而未进入标签开始状态从而使存在恶意js的标签无法被执行而是被当做字符串输入。
二、dom型XSS
dom型XSS主要的攻击方式为dom破坏和原型链污染
1.dom破坏
攻击者通过修改页面的 DOM 结构或 JavaScript 环境,注入恶意脚本并触发执行。
因为Javascript特别灵活
x
document.x,document.x.y
window.x,window.x.y
通过这样的方式和已将标签中的id或name属性改成我们的恶意js代码
javascript
<form id="location">
<input name="href" value="javascript:alert('XSS')">
</form>
<script>
document.location.href = "https://example.com";
</script>


2.原型链污染
js中对象没有的方法互相上从他的父类里去找,如果父类里面也没有就会继续向上从父类的父类里去找最终指向object这个对象,而原型链污染就是污染object里的prototype属性使得对象调用方法时向上找到我们污染过的方法
这里的的prototype属性里的方法是该对象子类所共享的。这里有三个属性prototype、peoto、constructor。
加入里我们设置三个元素a,b,c
a为构造函数
b,c为构造函数a的实例对象
b.proto=a.prototype
c.prototype=a.prototype
a.proto=object.prototype
object.proto==null
所以从这里我们就可以看出object.prototype是所有实例对象的源头
b.constructor=a
c.constructor=a
a.constructor=object
所以b.constructor.prototype===b.proto
在某些框架版本中__proto__会被过滤此时用constructor是同样的效果
在网页中后台代码一般出现merge、clone这样的函数就大概率会有原型链污染的漏洞
而原项链污染一般可以结合node.js实现RCE攻击
JavaScript中的lodash工具库存在危险的合并函数造成原型链污染:_.merge()
将上述三种属性过滤能有效避免这类合并函数造成的原型链污染
javascript
function safeMerge(target, source) {
for (const key in source) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue
}
target[key] = source[key];
}
return target;
}
三、存储型XSS
这个类型的XSS漏洞一般出现在网页可以评论、留言并且能够把数据存入数据库的地方
上传<script>/*......*/恶意js/*.....*/</script>这样的形式过滤恶意代码前后的系统过滤标签使得上传的恶意代码能够生效,但需被管理员触发,可窃取管理端的信息及管理员cookie等等危害风险较高