面试之-理解XSS、CSRF攻击原理与实践

一、XSS攻击

1、解释

xss是指攻击者在目标网站的网页上植入恶意代码,从而对正常用户进行劫持、获取用户隐私信息。

2、案例

假设有一个博客网站,允许用户输入评论,然后别的用户可以获取其他用户的评论。

前端页面:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
		<script>function addComment() {
				var kkk = $("#add").val() $.ajax({
					url: "http://localhost:8081/add",
					type: 'post',
					dataType: 'text',
					data: kkk,
					success: function() {
						alert("提交成功")
					},
					error: function(msg) {
						alert("error:" + msg);
					}
				})
			}</script>
	</head>
	<body>
		<h1>xss:</h1>
		<div>
			<input type="text" id="add" placeholder="输入评论">
			<button type="button" onclick="addComment()">提交</button></div>
	</body>

</html>

代码语言:javascript
复制
func main()  {

//简单起见,充当数据库
var comment string

http.HandleFunc(&#34;/get&#34;, func(writer http.ResponseWriter, request *http.Request) {
	header := writer.Header()
	header.Add(&#34;Content-Type&#34;,&#34;text/html; charset=UTF-8&#34;)
	header.Add(&#34;Access-Control-Allow-Origin&#34;,&#34;*&#34;)
	header.Add(&#34;Access-Control-Allow-Methods&#34;,&#34;POST,GET&#34;)
	writer.WriteHeader(http.StatusOK)
	_, _ = writer.Write([]byte(comment))
})

http.HandleFunc(&#34;/add&#34;, func(writer http.ResponseWriter, request *http.Request) {
	s,_ := ioutil.ReadAll(request.Body)
	comment = string(s)
	header := writer.Header()
	header.Add(&#34;Content-Type&#34;,&#34;text/html; charset=UTF-8&#34;)
	header.Add(&#34;Access-Control-Allow-Origin&#34;,&#34;*&#34;)
	header.Add(&#34;Access-Control-Allow-Methods&#34;,&#34;POST,GET&#34;)
	writer.WriteHeader(http.StatusOK)
})

http.ListenAndServe(&#34;:8081&#34;,nil)

}

攻击者评论时,输入以下评论内容:

然后一个正常用户通过url(http://localhost:8081/get)访问该评论,导致被攻击

image-20210617231211578

3、防范

通过前面的介绍可以得知,XSS 攻击有两大要素:

  1. 攻击者提交恶意代码。

  2. 浏览器执行恶意代码。

所有可以从以下方面进行防范:

1、对于用户的输入参数和服务端输出到HTML的结果都进行检查,进行必要的转义;

2、改成纯前端渲染,把代码和数据分隔开。

​ 纯前端渲染的过程:

  1. 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
  2. 然后浏览器执行 HTML 中的 JavaScript。
  3. JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。

在纯前端渲染中,我们会明确的告诉浏览器:下面要设置的内容是文本(.innerText),还是属性(.setAttribute),还是样式(.style)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。 但纯前端渲染还需注意避免 DOM 型 XSS 漏洞(例如 onload 事件和 href 中的 javascript:xxx 等,请参考下文”预防 DOM 型 XSS 攻击“部分)。

3、CSP

​ CSP的意义:防XSS等攻击的利器。CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。CSP 大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机。

二、CSRF攻击

1、解释

CSRF(Cross-site request forgery)跨站请求伪造:攻击者通过邮件、广告链接诱导受害者进入第三方网站。在第三方网站中,攻击者向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证(cookie),一般网站都是直接根据cookie判断是否是合法登录,由于受害者的cookie已经被获取了,所以被攻击网站就会认为是合法用户。这样就完成了冒充用户,并且对被攻击的网站执行某项操作的目的。

一次典型的CSRF攻击有着如下的流程:

  • 李四登录了网站 helloworld.com,并保留了登录凭证在浏览器中(Cookie)。
  • 法外狂徒张三通过邮件、小广告等手段引诱李四访问了网站 csrf.com。
  • 法外狂徒张三通过网站 csrf.com 向 helloworld.com 发送了一个请求:helloworld.com/action=xx。这…
  • helloworld.com 接收到请求后,根据cookie对请求者进行身份验证,由于cookie是合法的,helloworld.com就是认为是合法用户。
  • 法外狂徒张三就以受害者的名义执行了请求。
  • 攻击完成,法外狂徒张三在受害者不知情的情况下,冒充受害者执行了操作。例如转账等高危操作。

2、案例

首先我们写一个服务端响应:

代码语言:javascript
复制
func main()  {
	var num = 10
http.HandleFunc(&#34;/reduce&#34;, func(writer http.ResponseWriter, request *http.Request) {
	//验证cookie,成功num--
	cookie,_ := request.Cookie(&#34;id&#34;)
	if nil == cookie{
		writer.WriteHeader(http.StatusOK)
		fmt.Fprint(writer,&#34;cookie is nil&#34;)
	} else if cookie.Value == &#34;hahaha&#34;{
		num--
		writer.WriteHeader(http.StatusOK)
		fmt.Fprint(writer,num)
	}

})

// 这里假设用户是登录成功了,进入页面后,服务端种了一个cookie
http.HandleFunc("/view", func(writer http.ResponseWriter, request *http.Request) {
http.SetCookie(writer,&http.Cookie{
Name: "id",
Value: "hahaha",
})
writer.WriteHeader(http.StatusOK)
fmt.Fprint(writer,num)
})

http.ListenAndServe(&#34;:8081&#34;,nil)

}

第一步:

我们将如下链接="http://localhost:8081/reduce"通过邮件发送给被攻击用户,假设用户点击了,结果将如下:

image-20210617231341225

请求失败了,然后假设用户先访问了链接="http://localhost:8081/view",再访问的上述链接呢?

image-20210617231451257
image-20210617231535457

成功让值减一了,达到了攻击目的。

3、防范

  • CSRF(通常)发生在第三方域名。
  • CSRF攻击者不能获取到Cookie等信息,只是使用。

针对这两点,我们可以专门制定防护策略,如下:

  • 阻止不明外域的访问
  • 同源检测
  • Samesite Cookie
    • 提交时要求附加本域才能获取的信息
    • CSRF Token
  • 双重Cookie验证
同源检测

既然CSRF大多来自第三方网站,那么我们就直接禁止外域(或者不受信任的域名)对我们发起请求。

在HTTP协议中,每一个异步请求都会携带两个Header,用于标记来源域名:

  • Origin Header
  • Referer Header

这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个Header中的域名,确定请求的来源域。

==虽然CSRF大多数情况下来自第三方域名,但并不能排除本域发起。如果攻击者有权限在本域发布评论(含链接、图片等,统称UGC),那么它可以直接在本域发起攻击,这种情况下同源策略无法达到防护的作用。==

CSRF Token

前面讲到CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。

而CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击。

原理

CSRF Token的防护策略分为三个步骤:

1.将CSRF Token输出到页面中

2.页面提交的请求携带这个Token

3.服务器验证Token是否正确