web安全防御原理

web安全防御原理

web应用程序的几大防御机制:

1. 处理用户访问应用程序数据和功能,防止用户获得未授权访问。

比如未登录状态下访问, 应该给出什么内容,允许访问哪些区域,没有登录和普通账户登录去访问后台管理页面应该给出什么信息提示,这个就叫处理用户访问应用程序数据和功能,要是非正常的访问我们应该禁止或者给出提醒。

2. 处理用户对应用程序功能的输入, 防止错误输入造成不良影响。

在web安全上, 应该把所有用户的输入都视为不可信,这样就需要我们使用大量的防御机制来应对可能出现的安全问题和威胁,这个其中就包括处理用户对应用程序功能的输入。什么叫用户对应用程序功能的输入? 比如, 我提供一个web留言功能, 这个留言信息是直接写入数据库的,我想通过这个留言系统写上几句话发给他们,这个时候,这个web留言系统就叫应用程序功能, 我在上面留言在input框里写上话发给他们就叫用户对应用程序功能的输入。 这个其中还包括, 用户注册, 登录, 搜索等等。

3. 防范威胁/攻击者,确保当你的web/应用程序在真的遭到攻击时,可以保证运行正常的同时挫败攻击者。

比如我可以采用正则去过滤一些敏感标签或者当有人尝试对我进行攻击尝试时,给出一些警告性的提示或者直接返回下载一个20GB或者更大的文件让他下载,也可以直接显示出来让他的浏览器卡死或者干脆直接向他的电脑里植入木马(开玩笑的。。)再或者,万一你采用了各种办法,网站还是被人入侵了,而且还被人拿了webshell,黑客想改你的首页, 这个时候就需要部署防篡改措施,再万一运气不好, 黑客绕过了你的防篡改系统策略改掉了你的首页
你就要么需要做到通过备份自动再把文件替换回来或者当检测到严重的攻击行为时就马上下线该服务器换别的上或者干脆不换了, 这个有很多层,先就解释这么多。

4. 保证安全威胁检测的时效性,配置对应的管理,监控,log平台。

如果我遭到了攻击尝试,除了要进行阻拦和警告外, 还需要对它的行为进行记录,这个其中包括 http的访问请求、记录, 服务器的log记录, web server的log记录, 并且能够对其进行监控即时发现安全威胁做出合理的反应。

处理用户访问:

在一般的情况下, 咱们的web程序的用户主要会分为这几种类型(匿名的,通过注册验证的,管理员的), 现在随着技术的更替和发展迅速,高级点的又多了几个, 比如还有, 临时账户, 通过注册验证还没有通过认证审核的, 小管理员的(文章管理员,图片管理员,附件管理员等等)。 在这种情况下,我们就需要做到让对应用户只得到本应该属于它的内容, 比如,我的web邮件账户登录后只可能读到自己的邮件读不到别人的,老王睡觉睡的是自己的老婆不可能请求一个老王老婆来了一个老李等等。

大多数的web程序主要采用三层互联的安全机制来处理用户的访问

1. 身份验证
2. 会话管理
3. 访问控制

这三层只是按大了说, 细化了的话还会有很多方方面面, 我知道他是怎么回事, 也不想写这么多, 所以还是算了, 你可能听人说过或者在某本书里见过,对web程序访问处理机制是所有安全机制中最薄弱的环节, 为什么?

为什么说他薄弱,而且是最薄弱的环节是因为, 它的每一层都是容易受到攻击的, 我也不知道这样说标准不标准但是事实如此, 比如身份验证, 登录的时候绕过登录修改密码的时候跳过审核, 再比如会话管理 会话没有设置超时时间导致信息泄露风险, 修改令牌信息读取别人的内容 再比如访问控制 guest去访问admin的页面,如果在cookie里保存了userid把我的id改成别人的访问别人的信息, 我登录后然后通过自己遍历所有用户的id等等。 所以就能看的出来, 这些环节都是比较容易受到攻击的。

会话与令牌的不同: 我在一个web站上进行登录, 登录进行验证的时候, 这个时候就需要用户先与服务器建立一个会话, 然后服务器向用户发布一个令牌来识别当前用户的身份,当用户端收到一个令牌的时候标识身份后该令牌会随http请求发回服务器, 然后服务器再向用户返回对应的内容。

身份验证:

身份验证机制是应用程序处理用户访问的最基本机制,验证用户是指确定用户的真实身份。 如果不采用这个机制应用程序会把所有的用户当成匿名用户对待,这是最低一
级的信任。(也是最安全的)

在身份验证上面, 有可能造成的安全问题有, 我可能通过手段推测出存在的账户名或者通过暴力穷举的方式猜出账户密码。 input框过滤不全的情况下,如果web程序把注册或者登录信息存入了后台, 那样我就可以向后台注入任意脚本或者干脆直接绕过登录直接访问内容。 密码找回上面,在http直接返回验证码, 生成的验证码过短导致可以通过重放攻击方式穷举验证码。 前面说的比如在令牌里存user改成别人的user访问别人的内容等等。

会话管理:

我要进行登录, 想要从服务器获取我想要的内容的前提就是要先与服务器建立一个会话,当验证登录成功时我就可以通过发起各种http请求访问或者获取我想要获取的内容,这个时候,应用程序除了处理你之外还会处理各种人的请求, 包括通过验证的, 通过验证没有通过审核的, 匿名的这些, 为了对他们的访问请求实施有效控制,正确识别每一位用户并且完整处理他们的各种请求,就要进行会话管理。

会话管理的核心是靠令牌来识别用户和保证令牌的安全,就攻击面而言,会话管理的有效性取决于令牌的安全性, 为什么这么说? 因为令牌是用来识别用户的, 你令牌都不安全了就会造成篡权的情况,乱套了以后也就没法进行会话管理了, 因为这个时候已经无法正确识别用户。

少数应用程序功能不向用户发布令牌靠其他方式来识别用户,比如找回密码, 验证问题或者验证验证码这些。

访问控制:

处理用户访问的最后一个步骤是实施正确的决策,决定允许或者拒绝请求。 如果前面的机制运作都是正常的(身份验证、会话管理),应用程序就可以从收到的每一个请求中获得用户
对应的身份。在此基础上,应用程序需要决定是否允许用户所执行的请求操作或者访问相关数据。

要进行访问控制,就需要先进行精心设计它的逻辑,因为它的流程很复杂,所以我们设计的时候就要考虑到方方面面很多东西。 比如, 应用程序可以支持无数不同的用户角色(匿名的,注册后通过验证审核的,注册后没有通过验证审核的,被封禁的,管理新闻的,管理图片的,管理附件的……)每种用户角色的权限都不同,每名用户只允许访问部分和他权限对等的数据。

又因为实现这个访问控制逻辑很复杂,程序员设计的时候要考虑的地方很多,地方多了,难免就会忽略到一些地方,这个时候,就会有可能造成各种漏洞。

处理用户的输入:

以web安全的视角来考虑,即所有的用户输入都是不可信的,大量针对web程序的不同攻击方式都与提交不正确的输入信息有关,攻击者可以专门设计这种可能会造成程序出现不可预料执行结果的语句达到他的目的。所以这个时候,我们就要进行处理用户输入的工作。

所有程序和有关技术都有可能会出现输入方面的漏洞,对用户的输入进行确认是防御输入攻击的必要手段,当然任何一种防御方式或者手段都不可能是万能的,我们必须立体考虑整体安全框架。

输入是多样性的:

web程序会以各种不同的形式处理用户提交的数据,原因是因为向web程序提交数据有各种不同的方法和方式。 比如

我们可以通过input框提交。 input框示例 <code><input name = ‘username’ /></code>

可以通过url后面跟上自定义参数提交。 比如(http://www.test.com/ok.php?id=justhack&fok&ddr&crm)

可以通过火狐浏览器的插件修改header信息为自己构造的测试语句进行提交。 也可以使用 python的requests模块。

到这里,我们就知道了, 输入有各种方式, 他是多样性的。。。

在有些情况下, 我们需要对用户的输入进行严格过滤审核, 又在一些情况下, 我们需要把这个过滤适当放宽一些。 说的夸张一些, 防空导弹信令系统命令控制那里,如果是采用web框架开发的那就必须严格过滤,要是用户个人信息介绍栏里, 允许的输入就可以适当放宽一点, 允许一些字符啥的, 但是还是不能允许脚本标签, 也不能过滤的都太死了, 你要都过滤的死死的,不止黑客会骂你,用户也会骂你,意思是, 该松点的地方就得松, 该紧的地方就得紧, 不能失掉原则(恶意的输入和脚本标签必须过滤)

但是凡事都有例外,有的时候, 我们需要允许任意输入, 把一些看起来挺厉害有攻击性的语句以安全的方式显示出来, 比如文本化显示, 比较多的地方就是文章添加那里。

输入处理方法:

拒绝已知的不良输入:

我们可以建立一个已知的恶意行为,关键字库, 这个库就等于是一个黑名单。 当用户的输入符合黑名单内容时就对其进行拒绝然后允许其他内容, 但是人是活的, 技术也是一直在发展的, 只有黑名单是死的, 这个就造成了一个问题, 只要时间允许, 绕过黑名单来实施非正常输入行为是早晚的事, 比如, 你库你过滤了alert, 那可以换成prompt, 你过滤了select 可以换成SlEct, 再或者用注释隔断这些等等, 当然这些玩意有点过时了,但还是可以用用的, 再或者, 数据库因为更新的缘故出现了新特性, 你的关注度没跟上就会造成有可能别人通过新特性绕过你的黑名单这些。

所以, 仅仅使用拒绝已知的不良输入还是不够的, 必须要用组合拳。

接受已知的正常输入:

这个就是建立一个白名单, 里面放上一些允许的内容和模式, 不符合的都会被拒绝。 但是这种方式是有局限性的, 或者说是只适合某个别场景再或者说要是全局性使用只适合小范围的平台, 当然这种方式也是比较安全的, 因为白名单外的内容根本不可能被允许, 你也不会傻到在白名单内允许恶意内容。

净化:

有时候, 我们需要接受一些并不能保证安全的数据输入, 比如我允许使用<html> </html>和一些简单的js,但是还是不能让他使用类似alert, document, prompt这样的关键字 , 这个时候, 既不能确定他的输入是不是安全的, 也不能都拒绝, 所以这个时候可以允许他们输入, 只对输入的内容包含恶意信息的地方进行编码, 转义。 把危险字符植入页面前对其进行html编码就是防御跨站攻击的一种常用方法。

安全数据处理:

以不安全的方式处理用户输入的数据是很多web程序漏洞造成的根本原因(根本原因就是最本质的原因),在一般的情况下, 我们无需确认输入只需要确保处理过程是绝对安全的就可以了, 这个即安全编程方法。

语法检查:

在有的时候, 恶意攻击者并不需要输入特殊构造的语句对web程序展开攻击, 而是通过修改一些表单或者标识达到目的,而这些和正常数据是完全相同的, 这样就造成了你再怎么过滤我该黑你还是黑你的情况,所以这个时候, 就要对语法/表达式进行执行结果后二次确认检查是否改动,是否完整这些。

防范攻击者:

边界确认:

在早期web应用程序还不成熟的时候, 我们只需要维护网络确保网络出口安全稳定就可以了, 不需要担心太多东西, 黑客也没办法或者很难直接侵入内网, 后来随着技术的更替, web程序慢慢变得强大了,可以处理数据,可以进行交易, 正常生活很多都可以通过web实现了, 而他的作用也从单纯的显示展示变成了可以处理任务的强大程序, 而在一般情况下, web应用程序进行这些处理是要跟后台数据库进行交互的, 这些数据库基本上也都是在内网
这样就造成了, web被黑, 内网接着被黑的情况, 于是, 新的安全边界/标准出现了。。

可能有的人以为, 我可以在浏览器客户端这边验证用户的输入, 这样就安全了吗? 其实不是的, 你这样只防好人不防坏人的, 我可以拦截你发出的请求修改删除或者二次提交达到恶意目的,这个时候, 你在客户端那里的验证就跟没有一样差不多。所以, 我们不仅需要在客户端进行过滤, 还要在服务器端应用程序对恶意输入进行过滤。

有的人可能会以为, 只需要把互联网当成不可信的, 把我的程序当成可信的, 然后通过可信的程序接收并处理来自互联网的不可信数据, 然后这个时候数据和程序就是都是可信的了。。 其实这样是错的。。

原因有这么几点

1. 防御就那么几种, 黑你的人可以采用各种姿势, 单纯的靠仅有的机制防御很难做到都防住。

2. 你输入的东西, 是要经过前端页面,后端处理的, 这个中间有html,js,php(aspx,jsp…),mysql(nosql,oracle…)php.exe(IIS,tomcat…)而在这些环节转换的过程中你所输入的内容表现的形态在每一个环节都是不同的,有经验的攻击者可以控制在某个环节把语句组合成恶意语句,比如, 我可以在第一个环节就在脚本里嵌入二进制后的攻击语句, 可能走到脚本处理, 没反应, 走到数据库处理, 没反应, 走到php.exe, 他把代码翻译成二进制去执行的时候,就触发了攻击代码执行了非预料结果。 所以, 单纯的依靠外界防御, 这个是不行的。

3. 防御不同类型的基于输入的攻击可能会造成相互矛盾出现不可预料结果:

比如防止跨站需要把一个html标签编码, 而防止另外一种攻击要阻止的标签里可能就会包含预防跨站html编码后的部分标识,这样就会造成, 无法完全防御的情况。

为了解决这些问题, 分段边界确认显然是一种更有效的模型:

这个时候, 服务器端应用程序的每一个单独的功能或者组件把来自客户端的输入都当作潜在的恶意输入来源对待,除了客户端和服务器端外部边界外,应用程序在每一个边界执行对输入数据的确认, 这样就避免了冲突的情况(意思类似,在每一个转换边界执行数据确认, 比如html 到 php时, js到php时。)

一个边界确认的例子:

应用程序收到用户的登录信息, 表单确认每个输入仅包含合法输入和允许输入的长度,处理已知的不合法输入。

使用js结合正则对表单进行过滤, 对已存在正则中的过滤标签和数据/格式/进行删除或者格式化操作。

如果前面的处理都是正常的, 应用程序就会执行一个sql查询来检验输入的合法性, 在带入数据库查询前, 要对变量进行过滤可以攻击数据库的相关内容,如果不过滤, 就是一个典型的sql注入漏洞

比如, 一个$username和$passwd, 未经过任何处理就直接带入了sql查询, 那么, 这两个变量, user,pass, 就是两个可以注入的变量。

如果web应用程序采用了SOAP协议, 那么当用户成功登录后,就要对用户资料中的任何xml元字符进行编码。

(因为SOAP基于xml)

应用程序在用户的浏览器中显示用户的账户信息, 为了防止跨站攻击, 需要对植入返回页面的任何用户提交的数据进行html编码。

比如登录后的账户管理页面, 个人信息修改栏里, 我可以在那里的input里写上恶意语句,如果程序员没有对该处进行完整过滤,在我输入恶意语句后,当页面返回时,就会触发恶意的代码。

多步确认与规范化:

多步确认:

在多步确认检查用户输入时,如果采用删除或者编码恶意标签达到净化用户输入, 有可能会造成攻击者通过专门定制内容绕过你的过滤,比如

删除了<script> 可以通过<scr<script>ipt> 绕过, 当script被删除时, <scr ipt>就会被重新合并到一起,再或者, 没有过滤空格,可以通过

空格的方式让过滤直接中断执行。

数据规范化:

这里说的其实就是通过编码的形式过滤潜在的恶意输入, 但是,如果是在实施过滤之后才对数据进行规范化,那么就可以通过使用编码的形式绕过过滤。

首先, 说一下, 什么是在实施过滤之后才对数据进行规范化:

用户提交输入, 我经过客户端检测, 数据库检测,服务器端向客户端返回信息检测后, 再对这个显示的信息进行编码, 这就叫过滤之后才规范化。

比如, 我检测是通过检测标签检测的, 如果要是编码了, 那它检测的这玩意就是摆设了, 你该执行什么还是可以一样执行什么, 为什么会这样?

原因就是,应用程序响应输入会对输入的信息进行解码, 编码的时候无法识别, 解码的时候执行恶意脚本。。

为什么作者把这个多步确认与规范化单独来写, 而不是放到防御攻击者的大栏目里,就是因为, 这个是很难完全防御的一个攻击手段, 国内也有很多

黑客都精此攻击手法, 包括很多大厂商也都出过这方面的问题。 针对此攻击手段, 作者给出了两个防御建议

1. 通过递归过滤用户输入直到输入信息变成良性 (但是这种手段有bug,如果逻辑复杂的程序有可能会造成无限循环)

2. 结合场景来考虑。 (这个解释我感觉和等于0差不多, 说了等于没说)

这个其实还是得靠分段边界确认来防范 (内容在上面)

举个例子: 如果他拿组合的玩意绕过你的过滤, 你就可以通过空格的方式隔断让他的表达式无法组成。 但这个东西也说不准其实。

安全响应和及时检测:

任何应用程序的开发者在开发自己的程序之初都必须要做好一个假设, 即我的程序将会受到经验丰富的攻击者的攻击, 能够以可控的方式处理并应对这些攻击,是应用程序安全机制中一项主要功能。

为处理攻击者而采取的措施一般有以下任务构成:

1. 处理错误

比如程序出现不可预料执行结果, 类似的有, 黑客构造一些特殊的语句提交到web应用程序, 没有过滤全, 带入sql查询执行的时候sql执行出错了并且出错的信息被直接post到了页面上,这个里面会包含很多敏感信息,比如sql的类型,版本,web路径, 一些表结构等等, 这个时候就需要, 在前台尽可能的少显示信息或者用document.write提示, 在后台显示错误的详细信息给程序员查找错误提供方便。

2. 维护审计日志

有效的审计日志在调查对应用程序的攻击尝试时会发挥很明显的作用, 当入侵真正的发生时,有效的审计日志将会帮助程序所有者了解当时发生了什么情况。 比如采用了什么漏洞, 都访问了哪些页面, get了什么 post了什么等等, 要是用apache的话, apache有个自带的logs不用开启默认就有好像, 具体的可以翻翻网上的说明。

比如, 我通过post一段构造的sql语句对某网站进行了sql注入尝试, 如果网站方开启了审计日志, 就会留下这么一条信息

日期/POST/通过POST执行sql语句的具体页面或者路径/请求IP。   你也可以自己写一个日志记录, 做个后台管理啥的,但是日志必须文本化保存, 你不文本化保存恶意攻击者通过故意POST或者GET一些信息,有可能就会造成类似XSS这样的问题。

3. 向管理员发出警报

向管理员及时发出警报的目的是尽可能的把损失和影响降到最低, 如果对方已经侵入你的网站,审计日志可以帮助你了解他都干了什么, 如果攻击者已经进行了侵犯你利益的行为, 你就应该对入侵者尽可能最快的时间采取法律手段。 但是, 采取手段这个毕竟需要时间, 当务之急还是要先应对入侵者,例如, 检测到攻击后马上下线服务器, 阻止攻击者的IP或者账户这些。

在很多时候, 恶意攻击者可能需要采取反复提交或者重复尝试对你的web程序进行攻击尝试以达到他的目的, 比如穷举攻击这些, 都会在日志里生成大量记录, 它要是穷举1万次就会有可能生成一万条日志记录,这个时候,就会有可能影响你对其他用户行为的检查有可能就会忽略其他攻击行为,虽然可以通过程序对日志进行二次处理满足, 但是如果web工程庞大,用户众多,这个就会变得很麻烦, 所以,还是需要尽可能的把来自同一地址的相同攻击
合并到一个警报里。警报监控的反常事件一般有这么几种:

收到来自同一地址的反复大量请求 – 这有可能是人家正在ddos你有可能是正在进行爆破工作

交易反常 –  比如一个账户反复转入转出, 购买商品变成0或者与原价不符或者干脆变成负数

包含已知的攻击字符串 – 比如 index.php?download=/../…/etc/passwd 这种类似的, 比较常见的就是SQL注入这些。

请求中的数据被修改 –  这种多出现在近年流行的重放攻击里, 比如通过拦截提交表单修改关键id让别人支付或者修改金额支付, 文件上传的时候拦截from表单修改信息上传webshell等等。

在更多的时候, 我们还需要做到让警报日志更加精准, 这个时候, 最好的做法就是与前端处理进行联动, 通过识别攻击意图-检测攻击-尝试阻止攻击者-攻击成功还是失败了-他继续干了什么 来记录完整报告,比如我去购买一件本来价值500元的商品最后支付金额变成了1元, 虽然进行的操作都是没有明显恶意行为的, 但是价格与数据库记录价格明显不符, 所以这个时候就也是属于攻击行为了。 为了尽可能保护我们的资产不受到损害,除了记录
这些警示日志外,也可以在他进行这种操作的时候先给出警告提示(这样会吓跑一部分人,但是对用户体验并不好,不过可以采取人性化提示但是人性化提示又不太有警示作用所以这条还是算了,这条指的是当攻击者进行攻击尝试
时给出警告提示,其实小网站可以这样,没关系的说)。

4. 应对攻击者

除了向管理员发送警报外, 很多应用程序为了阻止潜在的恶意用户还有自己的内置安全机制或者模块。 (比如apache的 mod_security, linux下的iptables)

但是应用程序和服务是多种多样的, 很多攻击手段和路径都要求攻击者制定各种各样的手段和语句来探查有可能存在的各种漏洞, 我们可以采用输入确认机制来阻止大部分的这类攻击, 但是因为各种原因攻击者仍然会有可能绕过

过滤继续实施他的行为。这个时候,我们可以先通过自动化的检测来确定大部分可能存在问题的地方给予尽可能的修复, 再通过应用程序自动化阻止潜在的恶意攻击特征,或者阻止用户会话,封掉账户,中断响应回复。这种手段可以

阻止一部分小黑客,但是还是阻止不了大黑客,不过可以为应急响应赢来宝贵的时间。

阻止明显的攻击并不如直接修复漏洞实在, 但是在现实生活中, 我们虽然努力了, 进行了各种探查, 但是难免还会出现一些问题, 这个时候, 使用立体多层防御总要比使用某种单独的方式要好的多。因为所有的防御组合到一起会

加大黑客发现漏洞和利用漏洞的难度。

管理应用程序上的安全问题:

在一般情况下, 都是通过web界面对web程序进行管理, 它可以帮助用户管理员管理用户账户和角色, 添加文件, 删除信息, 上传图片, 甚至是管理日志的功能, 但是这种管理机制除了带来方便外也使它变成了受攻击目标,它吸引攻击者的地方主要在于可以通过侵入管理界面进行提权。

比如, 后台登录界面, 客户端边界检测没有过滤完整, 而数据库又没有对输入信息进行过滤, 导致可以绕过登录或者直接注入数据库, 从而直接拿到webshell。

没有对后台管理页面做好有效的权限验证,导致可以未授权访问后台管理页面, 不通过登录, 直接对你的web程序内容进行增删改查。

前台没有做好过滤, 后台返回页面也没有做好过滤 ,这样就会造成普通用户直接攻击管理员会话, 说的直白点就是, 打个比方, 前台有个留言本, 没有对输入数据进行有效转义, 后台返回留言信息页面也没有做好过滤,我在留言里插一个getcookie的js, 当管理员去后台留言信息处查看留言时, js执行, admin cookies被偷。

给大管理员的权限过大,比如普通管理员可能只拥有少部分的功能使用权限, 大管理却拥有很多功能,甚至是很多危险功能 ,比如sql查询, 直接操作物理系统的文件目录系统等等。

此条目发表在安全控制分类目录,贴了, , , , , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注