对于开发者而言,网络安全的重要性不言而喻。任何一处代码错误、一个依赖项漏洞或是数据库的端口暴露到公网,都会有可能直接送你上热搜。
那么,哪里可以找到详细的避雷指引呢?OWASP’s top 10 清单太短了,而且它更关注的是漏洞罗列,而非对预防。相比之下,ASVS 是个很好的列表,但还是满足不了实际需求。
本文这份清单将介绍 72 个实操要点,让你全方位保护你的 Web 应用程序。各位看官,准备入坑啦!
我一共划分了六个阶段,但并不是说你得学完全部才能上手工作,对于一些初级岗位,学到第三四个阶段就足矣~
这里我整合并且整理成了一份【282G】的网络安全从零基础入门到进阶资料包,需要的小伙伴可以扫描下方CSDN官方合作二维码免费领取哦,无偿分享!!!
【一一帮助网络安全学习,所有资源获取处一一】
①网络安全学习路线
②上百份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥HW护网行动经验总结
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析
接下来我将给各位同学划分一张学习计划表!
那么问题又来了,作为萌新小白,我应该先学什么,再学什么?
既然你都问的这么直白了,我就告诉你,零基础应该从什么开始学起:
接下来我将给大家安排一个为期1个月的网络安全初级计划,当你学完后,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web渗透、安全服务、安全分析等岗位;其中,如果你等保模块学的好,还可以从事等保工程师。
综合薪资区间6k~15k
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)
2、渗透测试基础(1周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等
3、操作系统基础(1周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)
4、计算机网络基础(1周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现
5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固
6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
那么,到此为止,已经耗时1个月左右。你已经成功成为了一名“脚本小子”。那么你还想接着往下探索吗?
综合薪资区间15k~30k
7、脚本编程学习(4周)
在网络安全领域。是否具备编程能力是“脚本小子”和真正网络安全工程师的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力。
零基础入门的同学,我建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习
搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP,IDE强烈推荐Sublime;
Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,没必要看完
用Python编写漏洞的exp,然后写一个简单的网络爬虫
PHP基本语法学习并书写一个简单的博客系统
熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选)
了解Bootstrap的布局或者CSS。
这部分内容对于咱们零基础的同学来说还太过遥远了,由于篇幅问题就不展开细说了,我给大家贴一个学习路线。感兴趣的童鞋可以自行研究一下哦,当然你也可以点击这里加我与我一起互相探讨、交流、咨询哦。
当然,只给予计划不给予学习资料的行为无异于耍流氓,这里给大家整理了一份【282G】的网络安全工程师从入门到精通的学习资料包,可点击下方二维码链接领取哦。
网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Q74i4Ob-1673698819150)(https://p3-sign.toutiaoimg.com/pgc-image/c17394c226e34335b44c26a62501ee71~noop.image?_iz=58558&from=article.pc_detail&x-expires=1674195200&x-signature=Qt9MBVcCyGJi3OfjHgu7PKcsnQ0%3D)]
众所周知,一个安全的应用需要对浏览器和 Web 服务器之间的所有连接进行加密。此外,建议禁用一些旧的密码套件和协议。使用 HTTPS 时,仅加密网站的“敏感”部分是不够的。如非这样,攻击者可以截获某个未加密的 HTTP 请求,然后伪造来自服务器的响应,返回恶意内容。幸运的是,HTTPS 目前是很容易做到的。我们可以通过 Let’s Encrypt 免费获得证书,加上 CertBot 免费续期。
继续我们的清单,下一个是 HSTS 它与 HTTPS 密切相关。
服务器可以用 HSTS 或 Strict Transport Security header 来强制进行加密连接。它表示需要一直使用 HTTPS 连接访问网站。
HSTS 可以防止 SSL 剥离攻击。所谓的 SSL 剥离攻击也就是:网络上的攻击者截获浏览器发出的第一个 HTTP 请求(通常是未加密的),并立即伪造对该请求的回复,假装是服务器并将连接降级为明文 HTTP。
值得注意的是,HSTS 仅在用户至少成功访问了一次应用程序的情况下才能生效。为了克服这个限制,可以把我们的网站提交到 https://hstspreload.org ,这样,各浏览器便可以将我们的域名通过硬编码写入到 HSTS 列表中。
如下:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
警告:
在实施 HSTS 时,将会强制进出该网站的所有网络请求均被加密,如果网站请求中仍然有纯文本,可能无法访问。所以,先设置一个小的 max-age 参数进行调试,如果一切正常工作,再加大这个值。调试成功后再加上预加载 (preload) ,把开启预加载保留在最后一步,因为关闭它是件很麻烦和痛苦的事情。
给 Cookie 加上 Secure 属性。此属性将防止 Cookie 在(意外或强制的)未加密的连接中泄漏。
Set-Cookie: foo=bar; ...other options... Secure
要避免 XSS(跨站点脚本)漏洞,可以采用下面两种方法:
此外,务必要正确配置模板引擎,从而可以自动对参数进行编码,并且不要使用任何可以绕过这种编码的“不安全”函数。不要把 HTML 放在回调函数、属性(不带引号)或 href/src 等诸如此类的地方。
要避免 JavaScript 端的 XSS(跨站点脚本)漏洞,切忌将不受信任的数据传递到可执行代码的函数或属性中。这类常见的函数或属性包括:
最好是能避免不可信的内容,但往往又不能完全避免:例如需要从远程获取 HTML 进行展示,或者需要允许用户用所见即所得的编辑器写文章,等等。
要避免这些场景中的 XSS(跨站点脚本)漏洞,请首先使用 DOMPurify 清理内容,然后在沙箱中进行内容呈现。
即使所见即所得的编辑库声称从 HTML 中移除了恶意内容,仍然可以通过重新净化和沙箱来处理,进一步确保安全。
还有一种常见的情况是,我们想在网页展示广告等内容。这种情况下简单采用 IFrame 是不够的,因为 same-origin 策略会允许跨域的 frame 将父级 frame (也就是我们的网站)的 URL 修改为一个钓鱼网站。因此,要记住使用 IFrame 的沙箱属性来避免此种情况的发生。
内容安全策略(CSP)可以很好地防御 XSS(跨站点脚本)攻击、点击劫持攻击等。所以,一定要用它!默认情况下,CSP 会阻止几乎所有的危险操作,所以额外的配置越少越好。如下:
Content-Security-Policy: default-src 'self'; form-action 'self'; object-src 'none'
它允许从 Web 应用程序的源代码加载脚本、样式、图像、字体等,但不允许加载其他内容。最值得注意的是,它将阻止内联脚本()的运行,从而更好地预防 XSS 漏洞。
此外,form-action:‘self’ 指令可防止在网站上创建恶意 HTML 表单(比如“您的会话已过期,请在此处输入密码”类似的表单),并将其提交到攻击者的服务器。
无论如何,都不要指定 script-src: unsafe inline ,一旦这样做,CSP 将形同虚设。
最后,如果你担心 CSP 会影响生产环境,可以先以 Report-Only 模式进行部署:
Content-Security-Policy-Report-Only: default-src 'self'; form-action 'self'
为 Cookie 设置 HttpOnly 属性,可以防止 Cookie 被 JavaScript 代码访问。一旦跨脚本攻击发生,该设置也会让黑客更难窃取到 Cookie 信息。当然,有些需要被 JavaScript 代码访问的 Cookie,就不能做这个设置了。
Set-Cookie: foo=bar; ...other options... HttpOnly
向用户提供下载功能时,在 header 中设置 Content-Disposition: attachment,从而避免 XSS 漏洞。该设置将禁止在用户浏览器直接渲染文件,从而避免 HTML 或 SVG 格式的下载文件可能引发的漏洞。如下:
Content-Disposition: attachment; filename="document.pdf"
假如我们想允许特定的文件(如 pdf)能在浏览器端打开,并且也确定这样是安全的,那么,可以针对该类型文件,将 header 省略掉或是将 attachment 换为 inline。
反射型文件下载(RFD)攻击往往通过构建一个 URL 从 API 下载一个恶意文件来实现。针对该类漏洞,可采用在 API HTTP 响应中返回带有安全文件名的 Content-Disposition header来防御。
为避免反跨站请求伪造漏洞,务必确保我们所采用的平台开启了反跨站请求伪造功能,并确保该配置发挥了应有的作用。
有一类与 OAuth 身份认证相关的跨站请求伪造漏洞是黑客让用户不经意间采用其账户进行登录。因此,如果有使用 OAuth 身份认证,务必确保对状态(state)参数的验证。
除了 POST、PUT、PATCH、DELETE 以外,不要使用其它 HTTP 方法进行数据更改。GET 请求一般是不包含在反跨站请求伪造机制中的。
为 Cookie 设置 SameSite 属性。SameSite 能防止大多数的跨站点请求伪造攻击,而且还可以防止许多跨站点泄漏的漏洞。
SameSite 属性有两种模式:宽松(lax)和严格(strict)。
宽松模式可以防止大多数跨站点计时和跨站点请求伪造攻击,但对基于 Get 请求的跨站点请求伪造漏洞无效。如下:
Set-Cookie: foo=bar; ...other options... SameSite=Lax
严格模式则可以防止该类基于 Get 请求的漏洞,以及反射型的跨站点脚本漏洞。然而,严格模式不适合常规的应用程序,因为它会中断身份验证链接。如果用户已登录某个网站,现在要在新的页面打开指向该应用程序的链接,则打开的新页面将不会为该用户自动登录。由于严格模式的限制,会话 Cookie 也不会随请求一起发送。严格模式设置如下:
Set-Cookie: foo=bar; ...other options... SameSite=Strict
会话固定攻击一般是在以下情形发生:
为了防止出现这种情况,程序中需要在身份验证通过后,创建一个新的会话 ID 返回给用户,而不是验证可能被动了手脚的 Cookie。
难道 Cookie 命名也能影响到网络应用程序的安全性?确实如此!将 Cookie 采用 __Host-** 的形式来命名,浏览器将:
该项设置示例如下:
Set-Cookie: __Host-foo=bar ...other options...
缓存是将访问过的网站、下载过的文件全部存储在硬盘的某个位置,直到有人手动删除它们。默认情况下,浏览器会对页面的一切内容进行缓存,从而加快访问速度、节约网络带宽。
要在公共网络环境保证信息安全,我们需要将所有 HTTP 响应设置一个合适的 Cache-Control header,特别是针对非公开的和动态的内容。
该项设置示例如下:
Cache-Control: no-store, max-age=0
另外一个可以有效保证用户退出后记录即被清除的 header 是 Clear-Site-Data 。当用户退出登录时,可以在 HTTP 请求中携带该 header。浏览器会清除该域名下的缓存、Cookie、存储以及执行上下文。大部分浏览器都支持该 header。
该项设置示例如下:
Clear-Site-Data: "*"
用户退出登录后,务必要对访问令牌和会话识别码进行失效处理。这样,即使攻击者从访问历史/缓存/内存等地方获取到这些信息,它们也不再有效。
此外,如果有单点登录,切记要调用单点登录的退出端口。否则,因为单点登录会话仍处于活跃状态,此时的退出将会无效,只要用户再次点击“登录”,即可自动登录。
最后,清理掉你可能用到过的 Cookie、HTML5 存储等。上面提到的 Clear-Site-Data 还未被某些浏览器支持,所以最好还是手工清除一下。
SessionStorage 类似于 LocalStorage,但对每个标签页都是独有的,而且在浏览器/标签页关闭以后将自动清除。
注意:如果要在系统内打开的多个标签页之间同步用户的授权信息,那就需要用事件来同步 sessionStorage 信息。
URL 设计的初衷就不是为了传输敏感信息。它会被显示在屏幕上,存储到浏览器历史记录,也容易随 referrer header 而泄漏,被记录在服务器日志等。所以,切忌在 URL 中传递敏感信息。
默认情况下,当从系统中链接到一个外部网站时,浏览器会设置一个 Referrer 的 header 来告诉该网站此次访问的来源。这个 header 包含了整个 URL 地址,这可能就涉及到一点隐私。
可以在 HTTP 响应中设置一个 Referrer-Policy 的 header 来禁止该默认行为:
Referrer-Policy: no-referrer
如果我们这样设置应用域名:https://www.example.com/app1/ 和 https://www.example.com/app2/,是非常危险的。因为浏览器会认为它们是同源应用,也就是同样的服务主机、端口和模式。正因为是同源应用,它们将对彼此有完全的访问权限。任何影响其中一个的漏洞都会同样影响到另外一个。
因此,我们需要给每个应用一个独立的域名。所以,这种情况下应该设置为:https://app1.example.com/ 和 https://app2.example.com/
注意:位于同一个域名下的子域名是可以为整个域名设置 Cookie 的。例如 app1.example.com 可以为 example.com 设置 Cookie,而这个 Cookie 也将适用于 app2.example.com。允许为一个站点设置 Cookie 有时会给会话固定等类型的漏洞以可乘之机。公共后缀列表可以用来应对该问题。此外,也可以通过将 Cookie 命名为 __Host- 来防止其被子域名所覆盖。
浏览器的安全模型大部分是依赖于同源策略,它可以防止应用的跨域读取。而 CORS(跨域资源共享)则是一种允许网站进行跨域资源访问的手段。所以,决定使用它之前,最好先搞清楚自己是否真的需要。
如果你在 api.example.com 的服务需要被来自 www.example.com 的 GET 请求访问,那么可以在 api.example.com 服务上指定如下header:
Access-Control-Allow-Origin: https://www.example.com
如果你有个公开的服务接口(比如说一个提供给互联网上 JavaScript 客户端使用的计算器服务),那么你可以指定一个随机的来源:
Access-Control-Allow-Origin: *
如果你只想让有限的几个域名访问它,那么可以在程序中读取请求的 Origin header,进行比对后处理。不过,建议使用现成的库来操作,不要徒手撸,很容易出错。
默认情况下,跨域资源共享是不带用户凭证的。但如果在 Web 服务器端指定如下 header,则将允许携带:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
这对 header 组合相当危险。因为它会使跨域访问具备已登录用户的权限,并使用该权限来访问网站资源。所以,如果你不得不使用它,务必小心为上。
仅允许所需要的 HTTP 方法,从而最小化攻击面。
Access-Control-Allow-Methods: GET
WebSockets 迄今还是比较新的技术,技术文档较少使用它难免会有些风险。所以,采用时务必要做到以下几点:
HSTS 也会影响 WebSockets ,它会自动将非加密的 WebSocket 连接升级到 wss://
如果想要做到双重保险,可以采用反跨站请求伪造令牌作为 URL 参数。但针对每个任务则需要创建一次性的独立令牌,而不要直接使用反跨站请求伪造令牌,因为后者主要是用来为应用的其它部分提供安全保障的。
如果系统可能会面临钓鱼攻击的威胁,说人话也就是,“如果存在这样的可能性:攻击者创建一个假的网站,骗取管理员/CEO 或其它用户的信任,从而盗取其用户名、密码和验证码”,那么就应该使用 U2F 令牌或客户端证书来防止这种攻击,这样的话即使攻击者有了用户名、密码和验证码也无法得逞。
备注:强调钓鱼防护对于一般用户而言往往会带来不必要的麻烦。然而,提供多一种可选项对终端用户而言也非坏事。此外,向用户提前告知钓鱼攻击的危险也是非常必要的。
跨站点泄露是一系列浏览器边信道攻击。这种攻击使恶意网站可以从其它 Web 应用程序的用户中推测出信息。
这种攻击存在已有时日,但是浏览器端却是最近才开始添加针对性的预防机制。可以在 这篇文章 中了解关于该类攻击的更多细节以及应该采取的安全控制措施。
其次,是服务器端的威胁防御,这里从应用系统、基础设施、应用架构、应用监控、事件响应等不同侧面,归纳了如下建议:
该类别的措施中最关键的一点就是尽可能严格地对所有用户输入进行合法性验证。适当的验证会使系统漏洞更难被发现和利用。对不合法的用户输入直接拒绝,而不要尝试去清洗。验证方面包括如下:
对终端用户不要显示堆栈记录或类似的调试信息。采用全局的异常处理器对异常进行处理,展现给浏览器端简单的错误信息。这样会使攻击者更难发现和利用系统中的漏洞。
对用户进行鉴权时可能会出现各种各样的问题:要抵御密码猜想攻击、用户枚举攻击,要管理密码重置、存储用户凭证,样样都不容易。就像密码处理一样复杂,我们普通人还是不要尝试了。
直接使用 auth0 等类似的工具来进行身份验证,采用一些广泛使用的、安全的软件模块来实现通信协议(常见的为 OpenID connect)。如果不想用 auth0 这类第三方的身份提供商,也可以自己搭建一个类似 KeyCloak 的服务来代替。
应用系统要默认对一切都进行鉴权,除非是一些静态资源、异常页面或登出页面。
万一有人破解了身份认证服务呢?如果存在这种担忧,直接上多重身份认证(说人话也就是:除了密码以外,还需要手机验证码)。这样就算身份认证服务被黑、攻击者可以冒充到任何人,还是无法知道手机收到的验证码。
权限控制虽不是件容易事,但也有妥善处理的方法:只要时刻记住不要在控制器方法中忘了对用户权限进行验证,从而带来用户越权的漏洞,包括:
为了进一步澄清权限管理工具,这里总结了一些要点:
注入类的漏洞有很多,而且都很相似,包括 SQL 注入、HTML 注入、XML 注入、XPath 注入、命令注入、SMTP 注入、响应 header 注入等等。名称不同但本质相同,相应地解决方法也类似:
这里不会深入太多细节,只要记住:不管你是什么协议,都谨记上面这点。后面会列举一些常见的注入类漏洞。
如果要避免 SQL 注入漏洞,那就记住绝不要自己用字符串拼接 SQL 查询语句。采用一个对象关系映射框架(ORM)来实现,可以让开发更高效、应用更安全。
如果想要构建更细粒度的查询,可以使用更底层一点的 ORM。
如果不能使用 ORM,那就尝试预处理语句,但也要小心这类语句会比 ORM 更容易出现错误。
警告:
ORM 框架也不是万能的,体现在两方面:一是,它对原生的 SQL 查询还是支持的,最好不要使用这类查询;二是,像其它任何软件一样,ORM 框架也会时不时被曝出漏洞。所以,还是遵循我们一而再再而三强调的策略:对所有输入进行验证,采用网络应用程序防火墙(WAF),并保持软件包的更新,这样基本就可以放心了。
如果可以避免,最好不要执行操作系统命令。如果不能避免,那最好遵循以下准则:
作为一种标记语言,XML 的危险性体现在它可以访问系统资源。XSLT 的一些实现甚至支持嵌入代码。因此,在处理时必须非常谨慎。
URL 注入经常会在以下情况发生:
flavour = request.getParam("flavour");
url = "https:/api.local/pizzas/" + flavour + "/";
return get(url).json();
如果 flavour 被设置为:
../admin/all-the-sensitive-things/
那么这个 API 请求将会变为 https://api.local/admin/all-the-sensitive-things/,是不是很凶险?
解决方案依然是采用合适的 URL 构建库来为 URL 传参,从而能正确地对参数进行编码。
就像 URL 地址一样,如果攻击者设法在路径中的某个地方偷偷地插入 …/…/…/ ,文件路径可能最终指向意料之外的位置。要避免这种情况,请创建一个类,采用这个类安全地构造路径,并验证最终路径是否在预期目录中。避免在文件路径中使用不受信任的数据,或者更好的是,完全避免使用文件系统,直接采用云存储。
如果允许用户写入服务器的文件系统,可能会出现各种各样的问题。改用云存储,或者在数据库中使用二进制 blob。
如果您必须访问磁盘,则应遵循以下指导原则:
不要使用 eval 或等效函数。找到一种其它的方法来实现代码执行。否则,不受信任的数据将有可能进行函数调用,从而在有机会在服务器上执行恶意代码。
对不受信任的数据进行反序列化是很危险的,很容易导致远程代码执行。
安装防火墙,会减少很多风险。ModSecurity 就是一个很好的开源选择。
HTTP desync,也称 HTTP 请求走私攻击,是指攻击者劫持随机用户向系统发出的 HTTP 请求。这类攻击一般在以下情况下发生:
那么该如何进行防范呢?一般是根据所采用的产品:
让目标应用隔离其他应用来运行。这样,即使发生了攻击事件,攻击者也不会有权限去访问未经许可的文件、系统或网络资源。因此,最好使用 Kubernetes 或一个云端环境来部署你的应用。如果因为某种原因必须使用一台服务器,那么可以手动采用 Docker 来约束应用。
即使通过容器来运行应用,也还是需要进一步采用 SELinux 或 AppArmor 策略来进一步地对应用做出约束,从而减少容器漏洞引发的威胁。
这种方法带来的好处是即使发生了被攻击事件,也能减少被攻击造成的损失。再次重申,列出所有的情形是不可能的,这里仅列举一些例子帮助大家理解:
攻击者通常需要建立一定的反向通信渠道来建立操控渠道或窃取数据。此外,一些漏洞也是需要外部网络连接才会被发现、被利用。
因此,不能让应用随便访问外部网络,包括 DNS。试下在服务器运行命令 nslookup www.example.com,如果运行成功,则说明你没有对外部网络连接做出适当的限制。如何处理此类问题,一般则取决于基础设施。
针对外部的 TCP/UDP/ICMP 连接,一般可以通过以下方式禁用:
DNS 处理起来稍微麻烦一点,我们通常需要允许对一些 hosts 的访问。
子域名劫持发生场景举例如下:
因此,需要随时留意你的 DNS 记录。如果需要处理的类似情况较多,强烈建议你做一个自动监控方案。
对连接互联网的网络应用程序不应该太过于信任。例如,不应允许它进行数据库直连。否则,当有人攻破应用程序时,整个数据库都将面临威胁。
相反,我们应该搭建多组件组成的架构,例如:
假如现在有黑客想要攻破我们的应用程序,即使成功,他也没有权限访问整个数据库,而只是利用某个用户的 token,进而访问该 token 所允许访问的那部分数据。
不要盲目相信内网的安全性,有很多方法可以攻破它。对于系统间的访问,全部采用 TLS(也就是 HTTPS)进行加密,最好在网络和系统两个层次对连接进行鉴权。
如果没有采用合适的敏感信息管理方案,就很难保持授权的短期性化、可审计性和秘密性。因此,建议采用 HashiCorp Vault 一类的工具来集中管理密码、加密 key 等类似信息。
集中收集日志到一个独立系统,比如 SIEM(安全信息和事件监控系统)。在这个系统中,可以在一些表征脆弱性、攻击的事件发生时进行报警。当严重威胁发生时,可以立即通知相关人员。
最重要的日志来源可能就是系统自身了。当有可疑行为发生时,系统应能引发异常,记录事件,可能的话,甚至可以自动封锁可能带来问题的用户或IP地址。常见可疑行为包括:
使用运行时安全监控工具如 Falco 来对异常系统访问进行检测。如果采用了 Kubernetes,那么 Falco 就特别有用。远程也可以对日志进行收集和监控。
假如我们制定了 SELinux 策略防止向外部的连接,但系统忽然向外部某个网站(例如 burpcollaborator.net)发起 HTTP 请求,那就需要立刻引起关注。又或者你的系统尝试访问 /etc/passwd。这两种情况都表示有人已经发现了我们系统中的漏洞。
对 Web 服务器软件,至少要对访问日志和错误日志进行收集,收集后发送到集中式的日志服务器。在突发事件响应时,这将辅助我们快速理清时间线。
如果你像上文推荐使用了网络应用程序防火墙(WAF),那么也对这个日志进行收集。但不用针对这个日志设置报警,因为它基本上会收到来自互联网各种各样的问题,而且不部分是你不用担心的。
一旦对我们的系统进行了监控和加固,攻击者将难以快速定位系统漏洞,即使最终发现,我们也能快速了解情况。
但仅了解情况是不够的,还需要做出如下准备:
2.6 开发管理
系统地考虑一下“可能会出现哪些问题”并据此做出调整。设计一个新的系统时,越早开始这一步越好。当对系统发生改变时,再重新梳理一遍这个过程。
例如:
小王:如果攻击者攻破了我们连接了互联网的服务器,怎么办?
小陈:那可就完蛋了!
小王:好吧!这就说明我们在这里存在着一个信任关系,我们认为连接了互联网的服务器是不会被攻破的。我们可以信任这一点吗?
小陈:未必吧!有一百种可能导致我们的服务器被黑掉,例如我们代码中存在的脆弱性,或者依赖中存在的脆弱性,或者是我们 Web 服务器所安装软件的脆弱性。
小王:好吧!那就让我们打破这层信任关系。接下来该做些什么呢?
小陈:我们这样来分解一下系统:创建一些内部的接口用来实际访问数据库,由此以来,前端的 Web 服务器就不能直接访问后台的所有东西。
小王:这是个好办法!除此以外,还有其它什么可能出问题呢?
小陈:嗯,如果黑客攻破了我们的内网呢?
小王:那所有东西都要丢失了,因为内网里服务器之间的连接都是未加密的。
小陈:……
这就是威胁模型,它不需要多么复杂。使用这种方式,来找出系统中可能存在的威胁。
通过技术控制手段,防止代码未经他人审核便提交入库。这是构建安全开发环境的基础,因为它可以做到:
开发人员应该有权限触发 Jenkins 构建,且 Jenkins 权限配置也仅该如此,不要再允许其它权限。单个开发人员应该不能在构建阶段引入任意代码。当然,如果像上文推荐的强制性地采用了代码审查,Jenkinsfile 也可以保存在版本管理工具中。
如果是构建容器镜像,可以把对镜像签名作为构建的一步。将签名密钥存储在安全的地方。构建阶段需要访问密钥,但是杜绝将密钥与 Jenkinsfile 一起存储在版本管理工具中。更好的方式是将密钥存储在 HashiCorp Vault 之类的地方,然后在构建时再进行拉取。
在持续集成管道中使用 SpotBugs 和 Find-Sec-Bugs(或者根据你所采用的技术栈进行选择)之类的工具。它们可以帮你在部署代码之前发现已知的漏洞。
此外,也可以作为 IDE 的插件安装在开发人员的电脑上,在代码迁入之前就运行这些工具进行检查。
应用程序中依赖的每个软件包都是一个风险来源。通过依赖,我们拉取了第三人的代码并在我们的应用服务器上执行,所以,必须要搞清楚我们依赖的这个软件包是什么,为什么会依赖它?
此外,严格控制应用服务器的对外连接,从而避免后门的存在。
使用 OWASP 依赖检查工具对依赖中常见的安全问题进行扫描。除了在持续集成管道中,也可以在开发人员的开发环境运行这些工具。
如果采用了容器化技术,可以使用 Trivy 等工具对容器镜像进行一些常规漏洞的扫描。
开发人员可以有权限到生产环境中部署,但是权限范围应该控制在前阶段已经构建和签名过的特定镜像,而不是直接访问生产服务器。如果是使用 Kubernetes,可以通过 Notary 或开放策略代理来验证待部署镜像的签名。
一个人的精力是有限的。我们不能期望每个开发人员都精通渗透测试或是安全工程师。正如你不能期望所有的安全专家都是优秀的开发人员一样。因此,可以在团队中设置一个专门关注安全的人员,主要与开发人员、架构师进行交流,帮助保护我们的应用程序并在团队中传播安全意识。
保证应用程序的安全性,光靠避免漏洞时不够的,必须全面通盘考虑,主动进行防御。这里对一些主要方法进行了总结:
感谢原作者的翻译授权:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHyurz6q-1673698819151)(https://p3-sign.toutiaoimg.com/pgc-image/b49df0ee127b45f2a6668b97cfc70435~noop.image?_iz=58558&from=article.pc_detail&x-expires=1674195200&x-signature=utroVnJrNwG9fOkdYJiGDVE8Cpo%3D)]
开放策略代理来验证待部署镜像的签名。
一个人的精力是有限的。我们不能期望每个开发人员都精通渗透测试或是安全工程师。正如你不能期望所有的安全专家都是优秀的开发人员一样。因此,可以在团队中设置一个专门关注安全的人员,主要与开发人员、架构师进行交流,帮助保护我们的应用程序并在团队中传播安全意识。
保证应用程序的安全性,光靠避免漏洞时不够的,必须全面通盘考虑,主动进行防御。这里对一些主要方法进行了总结: