对于开发人员来说,这很可怕!代码中的一个错误,依赖项中的一个漏洞,一个受感染的开发人员工作站,你的数据库在 Pastebin 中,你就上了新闻。
那么,到哪里寻求指导呢?OWASP 的前 10 名列表太短了,并且更多地关注列出漏洞而不是防御。相比之下,ASVS是一个很好的列表,但对于实际用途来说仍然有些神秘和模糊。
该清单是对黄金分割的尝试。我们将介绍 68 个实用步骤,您可以采取这些步骤从各个角度保护您的 Web 应用程序。让我们开始!
作为开发人员,您可以帮助减轻最终用户方面的一些威胁。他们包括:
让我们从针对这些威胁的对策开始我们的清单。
这个你可能已经知道了。加密用户的网络浏览器和网络服务器之间的所有连接。禁用一些较旧的密码套件和协议也没有什么坏处。
对网站的“敏感”部分进行加密是不够的。攻击者可以拦截单个未加密的 HTTP 请求,然后伪造来自服务器的响应,其中包含恶意内容。
幸运的是,现在 HTTPS 很容易。您可以免费获得证书 (LetsEncrypt) 和自动证书创建/管理 (CertBot)。
进一步阅读
- 2021 年 SSL/TLS 最佳实践
- 让我们加密
- 证书机器人
继续我们的清单,接下来是 HSTS,它与 HTTPS 密切相关。
HSTS或Strict-Transport-Security
是您的服务器可用于强制加密连接的标头。它说,从这里开始,始终使用加密连接 (HTTPS) 连接到我的域。
HSTS 将阻止所谓的SSL 剥离攻击,即网络上的攻击者拦截浏览器发出的第一个 HTTP 请求(通常是未加密的)并立即伪造对该未加密 HTTP 请求的回复,假装是服务器并降级从那时起与截获的明文 HTTP 的连接。
一个警告是,HSTS 只会在用户之前已经成功访问过应用程序的情况下保护应用程序。为了克服这个限制,您应该将您的站点提交到[https://hstspreload.org] ( https://hstspreload.org ),以便浏览器供应商可以将您的域硬编码到 HSTS 列表中。
例子
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
警告
实施 HSTS 时要注意。它将强制加密流量到您的网站,如果您仍然有纯文本,您的网站可能会崩溃。因此,从一个小的开始,
max-age
一旦你确信一切仍然正常运行,就可以增加它。并将预加载作为最后一步,因为取消很痛苦。
进一步阅读
- HSTS
- hstspreload.org
- ssls带
Secure
使用属性配置您的 cookie 。此属性将防止它们通过(意外或强制)未加密的连接泄露。
Set-Cookie: foo=bar; ...other options... Secure
进一步阅读
- 安全 Cookie
要避免 XSS(跨站点脚本)漏洞,请使用以下方法之一:
Twig
PHP、Thymeleaf
Java、Jinja2
Python 等。如果您使用模板引擎,请确保其配置正确以正确自动编码参数,并且不要使用任何绕过自动编码的“不安全”功能。并且不要将 HTML 放在危险的地方,例如事件处理程序代码、未引用的属性或 href/src。
进一步阅读
- XSS 攻击与预防
- 枝条
- 百里香叶
- 神社2
为避免 JavaScript 端的 XSS(跨站点脚本)漏洞,请勿将任何不受信任的数据传递到可能最终执行代码的函数或属性中。您必须在这里使用常识,但一些常见的嫌疑人是:
eval
, setTimeout
,setInterval
等innerHTML
, 反应的dangerouslySetInnerHTML
等。onClick
, onMouseEnter
,onError
等href
,src
等。location
,location.href
等。进一步阅读
- XSS 攻击与预防
- 基于 DOM 的 XSS
最好避免不受信任的内容。但有时,您必须从例如远程源检索原始 HTML,然后将其呈现在您的网站上。或者,也许您必须允许您的用户使用所见即所得的编辑器来撰写帖子。有很多用例。
为避免这些场景中的 XSS(跨站点脚本)漏洞,请先使用内容清理内容DOMPurify
,然后将其呈现在沙盒框架中。
即使您的 WYSIWYG 库声称要从 HTML 中删除邪恶,您仍然可以通过重新净化和沙箱化内容来打破这种信任关系(“我相信我的 WYSIWYG 库来清理内容”)。您破坏的信任关系越多,您的应用程序就越安全。
还有另一个常见的用例,您想在页面上显示例如广告。在这种情况下,使用 anIFRAME
是不够的,因为同源策略出于某种原因允许跨域框架将父框架(您的网站)的 URL 更改为例如网络钓鱼站点。在这些情况下,请始终使用sandbox
iframe 属性来防止这种情况。
进一步阅读
- XSS 攻击与预防
- DOMPurify
- 沙盒框架
内容安全策略 (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'
进一步阅读
- XSS 攻击与预防
- 内容安全政策
- 点击劫持攻击
- XS-泄漏
- XS-泄漏维基
HttpOnly
使用属性配置您的 cookie 。此属性将防止它们被 JavaScript 代码访问。这使得攻击者在成功进行 XSS(跨站点脚本)攻击时窃取它们更具挑战性。当然,您不能对需要通过 JavaScript 访问的 cookie 执行此操作。
Set-Cookie: foo=bar; ...other options... HttpOnly
进一步阅读
- XSS 攻击与预防
- HttpOnly
为了避免在向用户提供下载内容时出现 XSS(跨站点脚本)漏洞,请使用指示附件的Content-Disposition标头发送它们。这样,文件将不会直接在最终用户的浏览器中呈现,从而在 HTML 或 SVG 文件的情况下导致 XSS 漏洞。
Content-Disposition: attachment; filename="document.pdf"
假设您希望在浏览器中打开某些特定文件(出于可用性原因可能是 PDF 文档),并且您知道这样做是安全的。在这种情况下,您可以省略标题或更改attachment
为该inline
特定文件扩展名/扩展名。
进一步阅读
- XSS 攻击与预防
- 内容处置
一种称为反射文件下载 (RFD) 的攻击通过制作一个 URL,该 URL 作为恶意文件扩展名从您的 API 下载,反映其中的恶意负载。
您可以通过在 API HTTP 响应中返回Content-Disposition
带有保险箱的标头来防止这种攻击。filename
Content-Disposition: attachment; filename="api.json"
进一步阅读
- 反射文件下载
- 内容处置
为了防止跨站点请求伪造(CSRF) 漏洞,请确保您平台的反 CSRF 机制已启用并按预期工作。
进一步阅读
- CSRF 攻击与预防
存在与 OAuth/OIDC 相关的 CSRF 攻击,攻击者在不知不觉中使用攻击者的帐户登录用户。如果您使用的是 OAuth/OIDC,请确保您的库正在验证state
参数。
进一步阅读
- 在 OAuth 威胁模型中声明 CSRF
切勿使用除POST
,PUT
或进行任何更改之外的PATCH
任何内容。例如,请求通常不包含在反 CSRF 机制中。DELETEGET
进一步阅读
- CSRF 攻击与预防
使用SameSite属性配置您的 cookie 。SameSite 将阻止大多数CSRF(跨站点请求伪造)攻击,其中恶意网站代表您不知情的用户提交表单。
它还可以防止许多XS-Leaks。
有两种模式,Lax
和Strict
。
该Lax
模式非常适合防止大多数跨站点计时和 CSRF 攻击,除了基于 GET 的 CSRF 漏洞,您会在 GET 请求处理程序中错误地进行更改(例如,修改某些数据库记录)。该Strict
模式也可以防止这种错误被利用。
但是,该Strict
模式还有另一个强大的副作用。它也使得反射 XSS(跨站点脚本)漏洞实际上也无法被利用。
该Strict
模式不太适合大多数应用程序,因为它会破坏经过身份验证的链接。如果您的用户已登录并在另一个网站上打开指向该应用程序的链接,则打开的选项卡/窗口将不会为用户登录。由于严格模式,会话 cookie 不会与请求一起标记。
但至少SameSite
在Lax
模式下实现,这样做并没有什么坏处,而且它可以很好地防御 CSRF 和跨站点定时攻击。
Set-Cookie: foo=bar; ...other options... SameSite=Lax
...或者:
Set-Cookie: foo=bar; ...other options... SameSite=Strict
进一步阅读
- CSRF 攻击与预防
- SameSite cookie
- XS-泄漏
- XS-泄漏维基
我们清单上的下一个是会话固定攻击。以下是它们的工作方式:
JSESSIONID=ABC123
到您用户的浏览器中。攻击者有很多方法可以解决这个问题。JSESSIONID=ABC123
登录,在登录请求中提交攻击者选择的 cookie。为防止这种情况发生,请创建一个新的、经过身份验证的会话 ID 并将其返回给用户,而不是对可能被泄露的现有 cookie 进行身份验证。
进一步阅读
- 会话固定
您没想到会在应用程序安全检查表中找到 cookie 命名,对吗?这不是很广为人知,但说到饼干,名字很重要!命名您的 cookie__Host-Something
和网络浏览器将...
Set-Cookie: __Host-foo=bar ...options...
进一步阅读
- Cookie 前缀
- 会话固定
默认情况下,Web 浏览器会缓存他们看到的所有内容,以加快页面加载速度并节省网络带宽。
缓存是存储访问过的网站和下载的文件在磁盘上未加密的同义词,直到有人手动删除它们。
您的应用程序的用户应该能够相信,一旦他们注销,他们就会被注销,并且他们可以安全地离开(例如,图书馆)计算机。
Cache-Control
出于这个原因,您应该在所有包含非公共/非静态内容的 HTTP 响应中适当地返回一个名为的标头。
Cache-Control: no-store, max-age=0
进一步阅读 缓存控制
另一个用于确保在注销时清除用户数据的有用标头是新Clear-Site-Data
标头。当用户注销时,您可以在 HTTP 响应中发送它。浏览器将清除域的缓存、cookie、存储和执行上下文(在撰写本文时尚未实现)。大多数浏览器都支持它;Safari 显然仍然没有。
您可以按如下方式发送:
Clear-Site-Data: '*'
进一步阅读 清除站点数据
确保注销会使访问令牌/会话标识符无效。如果它后来从浏览历史/缓存/内存/等泄露给攻击者,它应该不再可用。
此外,如果有 SSO,请不要忘记正确调用单点注销端点。否则,注销将是徒劳的,因为仅单击“登录”按钮就会在 SSO 会话仍处于活动状态时自动将用户重新登录。
最后,清除您可能使用过的所有 cookie、HTML5 存储等。Clear-Site-Data
例如,Safari 尚不支持上述内容,因此您还必须手动清除数据。
它类似于 LocalStorage,但每个选项卡都是唯一的,并在关闭浏览器/选项卡后清除。因此,用户数据有可能泄露给下一个计算机用户。
注意 如果您想让您的用户在应用程序的多个选项卡中进行身份验证而不再次登录,则必须使用事件在选项卡之间同步 sessionStorage。
进一步阅读 会话存储
URL 地址并非设计为保密的。例如,它们会显示在屏幕上、保存到浏览历史记录中、与引荐来源头一起泄露以及保存在服务器日志中。所以不要把秘密放在那里。
我们清单上的下一个:推荐人政策。默认情况下,当您从您的应用程序链接到一个网站,并且用户单击该链接时,Web 浏览器将发送一个Referrer
标头来告诉该网站哪个网站链接到它。此标头包含整个 URL,这至少可能是一个隐私问题。
Referrer-Policy
您可以通过在 HTTP 响应中指定标头来禁用此行为:
Referrer-Policy: no-referrer
进一步阅读
托管这样的应用程序很危险:https://www.example.com/app1/
和https://www.example.com/app2/
. 浏览器认为它们是相同的origin
,即相同的主机、端口和方案。并且由于同源,他们将可以完全访问对方。任何影响 app1 的漏洞/恶意内容也会使 app2 处于危险之中。
出于这个原因,给每个应用程序一个他们自己的起源。所以解决方案可能是https://app1.example.com/
and https://app2.example.com/
。
注意 共享父域的子域仍然可以为整个域设置cookie。例如,app1.example.com
可以设置一个 cookie,example.com
然后将其发送到app2.example.com
. 能够为网站设置 cookie 有时会使会话固定等攻击成为可能。
如果您现在想知道.herokuapp.com 下的所有应用程序是否都存在漏洞,答案是否定的,因为公共后缀列表。此外,您可以通过将 cookie 命名为“ _ _ Host- ”来防止 cookie 被子域覆盖。
进一步阅读
- 同源政策
- Cookie 前缀
- 会话固定
- 公共后缀列表
Web 浏览器的安全模型主要基于同源策略,该策略阻止evil.example.com
阅读您的电子邮件,但仍允许您从code.jquery.com
. CORS 或跨域资源共享是一种允许其他网站违反该政策的方法。
因此,如果您决定需要它,请确保您知道自己在做什么。
进一步阅读
- 跨域资源共享
验证原点
如果您api.example.com
需要通过 GET 请求访问它,www.example.com
那么您可以在 上指定以下标头api.example.com
:
Access-Control-Allow-Origin: https://www.example.com
如果您有一个公共 API(假设您希望整个 Internet 从客户端 JavaScript 使用一个计算器),那么您可以指定一个通配符来源:
Access-Control-Allow-Origin: *
如果您有多个要允许但不是全部的域(例如,您只想允许 Google 和 Facebook 访问您的 API),那么您必须Origin
从请求中读取标头,将其与允许的域列表进行比较,然后根据需要返回一个标题。建议为此使用经过严格审查的库,而不是手动弄乱标题,因为很多可能会出错。
请注意“允许凭据”选项
默认情况下,CORS 不允许有凭据的请求,即携带用户(会话)cookie 的请求。但是,Web 服务器可以通过指定以下标头来允许这样做:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
这组 CORS 标头很危险,因为它允许https://www.example.com
像登录用户一样完全访问指定标头的网站。因此,如果您必须使用它,请非常小心。
验证方法
尽量减少攻击面并只允许您需要的 HTTP 方法是一个很好的做法。
Access-Control-Allow-Methods: GET
笔记
如果您不需要 CORS,请不要使用它。默认情况下,它被禁用。
进一步阅读
- 跨域资源共享
- 同源政策
清单上的下一个:WebSockets。WebSockets 仍然很新,几乎没有文档记录,使用它们时存在危险。所以请仔细阅读以下内容。
1.加密连接
就像你应该使用https://
代替http://
,使用wss://
代替ws:///
。
HSTS 也会影响 WebSockets,并且会自动将未加密的 WebSocket 连接升级到
wss://
! 冰雹 HSTS。
2. 验证连接
如果您使用基于 cookie 的身份验证并且 WebSocket 服务器与应用程序位于同一域中,则您可以继续使用现有会话进行 WebSocket 连接。请注意下一节有关原产地验证的内容,否则您会被搞砸的。
如果没有,您可以在应用程序中创建票证,即绑定到用户 IP 地址的一次性、有时间限制的身份验证令牌,可以对 WebSocket 连接进行身份验证。
3.验证连接的来源
了解 WebSocket 的一个关键是同源策略不会绑定它们。任何网站都可以打开与您的应用程序的 WebSocket 连接,如果您使用基于 cookie 的身份验证,则可以访问登录用户的信息。
因此,您必须在 WebSocket 握手中验证连接的来源。您可以通过验证Origin
请求标头来做到这一点。
如果您想要双重安全性,请将 CSRF 令牌作为 URL 参数输入。但是为作业创建一个一次性唯一令牌,不要使用您用来保护应用程序其余部分的 CSRF 令牌(因为在 URL 中发送某些内容可能会在许多地方泄漏)。
进一步阅读
- WebSockets 规范(查看第 10 节)
如果您的威胁模型包括网络钓鱼攻击,即“如果攻击者创建了一个从我们的管理员/CEO/等处窃取用户名、密码和 MFA 代码的假网站怎么办”,那么您应该使用U2F 令牌或客户端证书,即使攻击者拥有用户名、密码和 MFA 代码,也无法伪造。
注意 对于普通用户来说,实施网络钓鱼保护通常是多余的。但是,如果最终用户愿意的话,为最终用户提供使用服务的可能性(例如,他们的 YubiKeys )并没有错。但是,您始终可以做的是向用户展示有关网络钓鱼攻击的一般提示。
进一步阅读 创建不可钓鱼的安全密钥
XS-Leaks(或 Cross-Site Leaks)是一组浏览器侧通道攻击。它们使恶意网站能够从其他 Web 应用程序的用户那里推断数据。
这些攻击已经存在了很长时间,但浏览器最近才开始添加新的机制来防止它们。阅读本文,了解有关攻击和您应该实施的安全控制的详细信息。
此清单中最关键的事情之一:尽可能严格地验证所有输入。适当的验证将使许多漏洞难以发现和利用。拒绝无效输入,不要对其进行清理。
永远不要向最终用户显示堆栈跟踪或类似的调试信息。准备好全局异常处理程序,以捕获其他未处理的异常并向浏览器显示一般错误消息。这将使攻击者更难发现和利用您的应用程序中的漏洞。
在对用户进行身份验证时,有太多事情可能会出错。防御各种密码猜测和用户枚举攻击、管理密码重置、存储凭据等并非易事。这几乎就像密码学一样:凡人不应该自己做。
相反,使用身份提供者auth0
来验证用户并OpenID connect
使用广泛使用且安全的软件组件在您的应用程序中实现协议(通常)。如果您不想使用像 auth0 这样的第三方 IDP,您可以自行托管类似KeyCloak
.
进一步阅读
- 授权0
- OpenID 连接
- 钥匙斗篷
配置您的应用程序,以便默认情况下对所有内容进行身份验证。然后为静态资产创建必要的例外,也许还有一些端点,如登录页面或“退出”页面。
如果您想包括“如果有人完全破坏 IDP(身份提供者)怎么办?” 在您的威胁模型中,在您的应用程序中使用某种形式的 MFA(多因素身份验证)。即使 IDP 被黑客入侵并且攻击者可以在那里以任何人身份进行身份验证,攻击者仍然不会知道用户的应用程序本身的 MFA 机密。
访问控制并不总是那么容易,但你可以做对。只需集中注意力,就不会出现 IDOR(不安全的直接对象引用)漏洞,因为您忘记检查用户在某些单独的控制器功能中的访问权限。
为了稍微阐明权限评估器的方法,这里是它的症结所在:
int ownerId
。ownerId
等于用户的,则用户可以访问对象id
。ownerId
或类似的更复杂的访问控制,那么您可以设置(例如)一个完整的 ACL 系统。进一步阅读
- 不安全的直接对象引用
- 默认拒绝访问(Spring Security))
- PreAuthorize & PostAuthorize (Spring Security)
- 前置过滤器和后置过滤器(Spring Security)
多个漏洞属于“注入”类别,它们都是相似的。这些包括 SQL 注入、HTML 注入(XSS 的一种形式)、XML 注入、XPath 注入、LDAP 注入、命令注入、模板注入、SMTP 注入、响应标头注入……有很多“不同”的漏洞,在现实,同样的问题,同样的补救措施:
我们不会在本文中讨论每个注入漏洞,因为列表将是无限的,所以无论您正在构建什么协议,只要记住这条规则即可。我们将在我们的清单中介绍一些更流行/有趣的,例如 SQL 注入。
为避免 SQL 注入漏洞,切勿通过字符串连接构造 SQL 查询。如果可以,请使用 ORM(对象关系映射器)。ORM 将使开发更快,应用程序更安全。
如果您想对查询进行精细控制,请使用低级 ORM(通常称为查询构建器)。
如果您不能使用 ORM,请使用准备好的语句,但要小心,因为它们比 ORM 更容易出现人为错误。
警告
ORM 框架在两种意义上都不是灵丹妙药。
首先是它们仍然具有支持原始 SQL 查询/部分查询的功能。只是不要使用这些功能,你就是黄金。
二是ORM框架时有漏洞,就像任何其他软件包一样。因此,请遵循其他好的做法:验证所有输入,使用 WAF 并保持你的包是最新的,你就可以开始了。
进一步阅读
- SQL 注入攻击和预防
如果可以避免,请不要执行操作系统命令。它总是有点狡猾。
如果必须这样做,您可以按照以下准则避免命令注入漏洞和相关问题:
list
数据类型。切勿将命令创建为单个字符串。curl
允许用户指定-o
参数,您将允许攻击者写入本地文件系统。curl
示例为例,您可能希望允许用户检索诸如此类的网站,https://www.appsecmonkey.com/
但如果攻击者检索file:///etc/passwd
了呢?http://
or开头https://
,您是否希望攻击者访问http://192.168.0.1/internal_sensitive_service/admin
或对内部网络进行端口扫描?yourcompany.local
,是否有任何东西阻止攻击者创建指向的公共 DNSwww.example.com
记录192.168.0.1
?答案是不。可以办到。进一步阅读
- 命令注入
XML 是一种危险的标记语言,它包含用于访问系统资源的功能。XSLT 的一些实现甚至支持嵌入式代码。出于这个原因,您在处理它时必须非常小心。
document
XSLT。禁用xinclude
. 禁用文档类型定义。禁用外部实体。启用 DOS 保护。具体选项会因实现而异,请对您选择的解析器进行一些研究。进一步阅读
- XXE 攻击与预防
- 寻找 XXE 以获得乐趣和利润
- WS 攻击
当你有这样的事情时,就会发生 URL 注入:
flavour = request.getParam("flavour");
url = "https:/api.local/pizzas/" + flavour + "/";
return get(url).json();
有人输入这样的值:
../admin/all-the-sensitive-things/
这会导致 API 调用返回响应,https://api.local/admin/all-the-sensitive-things/
而不是像开发人员预期的那样返回比萨端点。
与往常一样,解决方案是使用适当的 URL 构造库来参数化 URL,以便对值进行正确编码。
就像 URL 地址一样,如果攻击者设法../../../
在路径中的某处偷偷摸摸序列,文件路径也可能最终指向不需要的位置。为避免这种情况,请创建一个安全地构造路径并验证最终路径是否在预期目录中的类。避免在文件路径中使用不受信任的数据,或者更好的是,完全避免使用文件系统,而更喜欢例如云存储。
进一步阅读
- 路径遍历攻击
当允许您的用户编写服务器的文件系统时,有无数可能出错的事情。请改用云存储,或者如果这对您不起作用,请在数据库中使用二进制 blob。
如果您绝对必须访问磁盘,这些指南可以帮助您确保安全:
不要使用eval
或等效功能。想办法在没有它们的情况下实现你的目标。否则,将存在不受信任的数据到达函数调用的风险,并且有人会在您的服务器上执行任意代码。
不可信数据的反序列化是一种危险的操作,很容易导致远程代码执行。
进一步阅读
- OWASP 反序列化备忘单
在您的应用程序前面放置一个 Web 应用程序防火墙产品。这将使许多漏洞更难被发现和利用。ModSecurity 是一个很好的开源选项。
进一步阅读
- 国防部安全
有一种称为“HTTP Desync”或“Request Smuggling”的攻击,如果满足以下条件,攻击者可能会做各种令人讨厌的事情,例如窃取收集到 Web 应用程序的随机用户的 HTTP 请求:
Content-Length
在Transfer-Encoding
不规范化请求的情况下传递它们。Content-Length
,而应用程序服务器将使用Transfer-Encoding
.那么如何保护自己呢?取决于产品,但一般来说:
进一步阅读
- HTTP 异步攻击:请求走私重生
单独运行您的应用程序,以便在发生违规事件时,攻击者不会不必要地访问不需要的文件、系统或网络资源。因此,最好使用 Kubernetes 或无服务器云堆栈之类的东西来部署您的应用程序。如果您因任何原因被迫使用裸服务器,请手动运行例如 Docker 来约束应用程序。
进一步阅读
- 码头工人 101
即使您在容器中运行应用程序,使用 SELinux 或 AppArmor 策略进一步限制它也是值得的。这将使利用容器逃逸漏洞变得非常困难,以及其他好处。
进一步阅读
- SELinux 图画书
- 应用装甲
当出现问题时,这通常会限制损坏。再一次详尽的列表是不可能的,但这里有几个例子可以理解:
攻击者通常需要某种反向通信通道来建立命令和控制通道和/或窃取数据。此外,一些漏洞需要发现和利用出口网络连接。
出于这个原因,您不应该允许从您的应用程序到外部世界的任意连接,这包括 DNS。如果您可以nslookup www.example.com
从服务器成功运行,则说明您没有正确限制出口。
你将如何处理这取决于你的基础设施。
出口 TCP/UDP/ICMP 通常可以通过以下一项或多项禁用:
DNS 有点棘手,因为通常需要允许某些主机使用它。
子域接管是这样发生的:
example.com
。www.my-cool-campaign.com
并创建了一个CNAME
from campaign.example.com
to www.my-campaign.com
。www.my-cool-campaign.com
到期。CNAME
指向campaign.example.com
过期域的指向。campaign.example.com
) 下有一条 DNS 记录指向攻击者控制的域。www.my-cool-campaign.com
,可从其访问https://campaign.example.com
因此,请注意您的 DNS 记录。如果您必须处理大量这样的域名,强烈建议使用自动化的监控解决方案。
进一步阅读
您不应该对面向 Internet 的 Web 应用程序过于信任。例如,它不应该直接访问数据库。否则,当有人闯入面向 Internet 的应用程序时,您的整个数据库都将丢失。
相反,将您的架构分成多个组件,例如:
www.example.com
将在 上对您的用户进行身份验证auth0
。www.example.com
连接到内部 API ,然后在调用内部 API 时将其作为标头传递。api.example.local
access-token
auth0
Authorization
api.example.local
将根据(最终用户的)访问令牌强制执行访问控制,并适当地读/写数据库。现在,如果攻击者完全破坏了您的www.example.com
应用程序,则攻击者将无法完全访问整个数据库,而只能访问其访问令牌当时恰好在内存中的个人用户数据。
不要相信您的内部网络是安全的;有很多方法可以破坏它。使用 TLS 加密所有系统到系统的连接(即使用 HTTPS),并最好在网络和应用程序级别对连接进行身份验证:
如果没有适当的秘密管理解决方案,就很难让凭证保持短暂的生命周期、记录审计日志并且不让它们暴露在人眼中。出于这个原因(以及许多其他原因),建议使用 HashiCorp vault 之类的工具来集中管理集成机密、加密密钥等。
进一步阅读
- HashiCorp 保险库
你永远不知道什么时候出了问题,所以要备份。
你的整个数据库都在备份中,所以要非常小心你允许谁访问它们。强烈建议对备份进行加密,这样您就不必太相信没有人可以访问它们。只是不要丢失加密密钥。
这是至关重要的。养成检查备份是否有效的习惯,当出现问题时,您实际上可以恢复它们。
将日志集中收集到系统中,例如 SIEM(安全信息和事件监控),您可以在其中针对指示漏洞或攻击的特定事件触发警报。配置警报通道,以便相关人员在发生重大威胁时立即知道。
可能最重要的日志源是您的应用程序本身。当可疑行为发生时,您应该提出异常,记录事件,甚至可能自动锁定似乎造成问题的用户/IP 地址。
此类事件可以是(这些只是示例,具体情况在很大程度上取决于您的应用程序):
使用 Falco 等运行时安全监控工具来检测异常系统调用。如果您碰巧使用 Kubernetes,Falco 特别有用。还可以远程收集和监控这些日志。
进一步阅读
- 法尔科
如果您有一个阻止传出连接的 SELinux 策略,并且您的应用程序突然尝试向 eg 发出 HTTP 请求burpcollaborator.net
,那么立即了解它会非常有用。或者您的应用程序可能会尝试访问/etc/passwd
. 这两种情况都表明有人已经在您的应用程序中发现了一个严重的漏洞。
至少从您的 Web 服务器软件中收集访问日志和错误日志,并将它们也发送到中央日志服务器。这将有助于在事件响应中绘制时间表。
如果您使用上述推荐的 WAF,请同时收集这些日志。但不一定会触发他们的警报,因为通常,WAF 产品会受到来自 Internet 的各种垃圾的轰炸,大多数时候您不必担心。
一旦你的监控和加固到位,攻击者就不容易发现漏洞,成功利用漏洞的速度会很慢,而且你会很快了解这些尝试——这是个好地方。
但是了解攻击并减缓攻击者的速度是不够的。你仍然需要对它们做点什么。因此,请准备好人员、工具和流程:
经历一个思考“可能出什么问题”的过程,然后采取一些措施。最好在开始设计系统时从一开始就这样做,但开始永远不会太晚,无论如何,当您将更改引入系统时,您应该重新访问此过程。
例如:
Jim:如果攻击者破坏了面向 Internet 的 Web 服务器怎么办?
鲍勃:那我们就完蛋了。
Jim:好的,所以我们在那里建立了信任关系,我们相信面向 Internet 的 Web 服务器不会被盗用。我们真的可以相信吗?
Bob:嗯,不,有无数的事情可能导致那个东西被黑客入侵,例如我们自己的代码中的漏洞,或者我们使用的依赖项中的漏洞,或者我们的 Web 服务器软件中的漏洞。
吉姆:对。所以让我们打破这种信任关系。但是怎么做?
Bob:让我们打破整体并创建一个内部 API 来执行实际的数据库访问。然后前端 Web 服务器将无法一次访问所有内容。
吉姆:好主意。那么还有什么可能出错的呢?
Bob:那么,如果攻击者破坏了我们的内部网络怎么办?
Jim:一切都会丢失,服务器到服务器的连接都是未加密的。
鲍勃:……
这是威胁建模,它不必复杂或可怕。用它来发现危险的信任关系,然后打破这些关系。
实施一项技术控制,以防止代码在没有至少一两个其他开发人员批准的情况下进入存储库。这是您安全开发生命周期的基础,因为现在发生了两件事:
进一步阅读
- GitLab - 所需的批准
- BitBucket - 检查合并拉取请求
- Azure DevOps - 使用分支策略提高代码质量
单个开发人员应该能够触发例如 Jenkins 构建,但应该将 Jenkins 配置为允许这样做,仅此而已。个人开发人员不应该能够将任意代码引入构建阶段。但是,您可以将 Jenkinsfile 保留在源代码控制中,只要像上面推荐的那样在技术上强制进行同行评审过程。
签署工件。例如,如果您正在构建容器镜像,请将镜像作为构建的一部分进行签名。安全地存储签名密钥。构建阶段需要访问密钥,但不应将它们与 Jenkinsfile 一起存储在版本控制中。最好将密钥保存在例如 HashiCorp 保险库中,并在构建时提取它们。
进一步阅读
- 内容信任的自动化
- Jenkins - HashiCorp Vault 插件
在 CI 管道中运行诸如 SpotBugs + FindSecBugs(或适用于您选择的技术的类似工具)之类的工具。这将帮助您在部署代码之前发现代码中的一些已知漏洞。
您还可以在开发人员的工作站上运行这些工具(例如作为 IDE 插件),甚至在将它们检查到版本控制之前就可以发现问题。
进一步阅读
- 斑点虫
- 查找安全漏洞
您依赖的每个软件包都是一种风险。您正在从其他人的存储库中提取代码并在您的应用程序服务器上执行它。所以要注意你依赖什么以及如何依赖。
由于额外的强化限制了来自您的应用程序服务器的出口连接(本文前面描述),以防止任何后门“回家”。
进一步阅读
- Gradle 依赖验证
运行诸如 OWASP DependencyCheck 之类的工具作为 CI 管道的一部分,以捕获您可能正在使用的一些依赖项,这些依赖项中存在已知的安全问题。
您也可以在开发人员的工作站上运行这些工具(但也要在最重要的 CI 管道中运行它们)。
进一步阅读
- OWASP 依赖检查
如果您使用容器,请使用 Trivy 等工具扫描创建的容器映像以查找已知漏洞。
进一步阅读
- 特里维斯
个人开发人员很可能有权部署到生产环境,但只有在之前阶段构建和签名的特定映像才能部署。访问生产机密或直接访问服务器应该是不可能的。验证部署映像的签名,例如,如果您使用的是 Kubernetes,则通过 Notary 和 Open Policy Agent 验证容器签名。
进一步阅读
- Docker 内容信任
- 使用 Notary 和 Open Policy Agent 确保 Kubernetes 上的内容信任
一个人的痴迷程度是有限度的。你不能期望每个开发人员都是熟练的渗透测试员或安全工程师。正如您不能期望所有安全专家都是优秀的开发人员一样。
因此,向您的团队介绍以安全为重点的人员通常是一个好主意,以便与开发人员、架构师等进行讨论,并帮助保护您的应用程序并在团队中传播安全意识。
进一步阅读
- 什么是安全冠军?
保护您的应用程序不仅仅是避免漏洞。总结一些主要思想: