本文最后更新于 389 天前,其中的信息可能已经有所发展或是发生改变。
题目来源:deman
感谢 deman 童鞋为大家提供的面试题。我先来抛砖引玉,提供一些自己的见解,欢迎积极讨论,一起打造最全的知识题库
反射型XSS、存储型XSS、DOM型XSS漏洞的区别
反射型 XSS (Reflected XSS)
基本原理
攻击者将恶意脚本注入到用户可控的参数中(如 URL 参数、Form 表单等),然后携带参数提交请求,这些参数被服务端处理后返回给浏览器,再由浏览器解析执行恶意脚本,达成攻击的目的。
攻击流程
用户构造 –> 服务端接收&处理 –> 服务端返回给浏览器 –> 浏览器解析
特点
到达服务端,但并未存储,所以此类攻击通常需要诱导用户点击链接或者输入指定内容才能达成效果,点击一次,攻击一次,危害中等。3
代码示例
前端:
<input type="text" id="name">
<button onclick="submit()">提交</button>
<script>
// 点击“提交”按钮时的操作
function submit() {
// 获取 id 为 name 的 input 输入框内容(此输出框的内容用户可在页面上随便填写
var name = document.getElementById('name').value;
// 将获取到的 name 以 url 参数的形式,传递到后端,其中 encodeURIComponent 是对 name 进行了 URL 编码
window.location.href = 'http://localhost:8080/reflected_xss_example?name=' + encodeURIComponent(name);
}
</script>
后端:
@WebServlet("/reflected_xss_example")
public class Reflected_xss_example_Servlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception{
// 获取来自前端的 name 参数内容
String name = request.getParameter("name");
// 将获取到的 name 的内容以 html 中的 p 标签的形式输入到前端页面
response.setContentType("text/html");
response.getWriter().println("<p>" + name + "</p>");
}
}
示例代码攻击流程分析:
- 假设前端输入 name 内容为
</p><script> alert(document.cookie) </script>
- 点击“提交”按钮时,windows.location.href 指向的就是 http://localhost:8080/reflected_xss_example?name=%3C%2Fp%3E%3Cscript%3E%20alert(document.cookie)%20%3C%2Fscript%3E
(当然,也可以直接将这个 url 发送给其他用户,诱导其点击) - 后端接收到 name 参数,并将其返回给前端,在前端就会生成如下代码:
<p></p><script> alert(document.cookie) </script></p>
p 标签闭合,script 标签内的 js 代码被解析,弹出当前页面中的 cookie 的值。至此,就触发了反射型 XSS 攻击。
存储型 XSS (Stored XSS)
基本原理
攻击者将恶意脚本注入到用户可控的参数中,然后携带参数提交请求,这些参数被服务端处理并存储到数据库,当用户再次访问到该内容时再由浏览器解析执行恶意脚本,达成攻击的目的。
攻击流程
用户构造 –> 服务端接收&处理 –> 服务端存储 –> 用户(可以是任意用户)再次调用 –> 服务端返回 –> 浏览器解析
特点
到达服务端,并存储,任意用户只要调用读取,均会造成攻击,且长期有效,危害较高。
代码示例:
前端:
<input type="text" id="name">
<button onclick="submit()">提交</button>
<script>
// 点击“提交”按钮时的操作
function submit() {
// 获取 id 为 name 的 input 输入框内容(此输出框的内容用户可在页面上随便填写
var name = document.getElementById('name').value;
// 将获取到的 name 以 url 参数的形式,传递到后端,其中 encodeURIComponent 是对 name 进行了 URL 编码
window.location.href = 'http://localhost:8080/stored_xss_example?name=' + encodeURIComponent(name);
}
</script>
后端
@WebServlet("/stored_xss_example")
public class Stored_xss_example_Servlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception{
// 获取来自前端的 name 参数内容
String name = request.getParameter("name");
// 伪代码,将获取到的 name 的内容存储到数据库
messageService.addMessage(name);
}
}
@WebServlet("/getname")
public class Getname_Servlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception{
// 从数据库中读取 name 的值。
String name = messageService.getMessage();
// 将获取到的 name 的内容以 html 中的 p 标签的形式输入到前端页面
response.setContentType("text/html");
response.getWriter().println(<p id="name">"+ name +"<p>);
}
}
示例代码攻击流程分析:
- 假设前端输入 name 内容为
</p><script> alert(document.cookie) </script>
- 点击“提交”按钮,携带参数调用 stored_xss_example 接口,并将 name 参数的内容存储到数据库中。
- 任意用户只要调用 getname 接口(无需诱导点击 URL,且长期有效),均会从数据库中读取 name 属性,从而将恶意代码注入到前端页面,引发攻击。
DOM 型 XSS(DOM-based XSS)
基本原理
攻击者利用 js 操作 DOM 的方式来注入执行恶意脚本。
攻击流程
用户构造 –> 浏览器解析
特点
与服务器无关,直接在操作人本地浏览器中执行,通常需诱导用户输入指定参数内容或者点击链接(点击链接其实是使用 URL 的方式携带指定的参数,根本原理还是输入内容),危害较小。
代码示例:
前端:
<input type="text" id="name">
<button onclick="submit()">提交</button>
<input type="text" id="result">
<script>
function submit() {
var name = getUrlParameter('name');
document.getElementById('result').innerHTML = 'Hello, ' + name + '!';
}
</script>
示例代码攻击流程分析:
- 用户在 name 输入框中输入内容:
<script>alert('XSS')</script>
- 点击“提交”按钮
- js 方法将 name 内容填充到名为 result 的 DOM 节点中,从而触发攻击。
总结:
- DOM 型 XSS 无服务器参与,需要诱导目标用户操作,点击一次攻击一次,危害较低。
- 反射型 XSS 有服务器处理过程,但不存储,也需要目标诱导用户操作,点击一次攻击一次,危害普通。
- 存储型 XSS 有服务器处理并存储,任意读取该数据的用户均会收到攻击,攻击范围广,且具备持久性(如不主动删除则一直存在),危害较高。