关于前端安全的几个提示
作为前端开发人员,我们最关心的是性能、SEO 和 UI/UX——安全性却经常被忽略。
我们应该记住,就安全性而言,前端现在与后端或 DevOps 承担着同样的责任。前端可能会发生几千种恶意攻击。
常见攻击
1. 不受限制的文件上传
这是一种将恶意文件上传到服务器然后对系统执行的攻击方式。攻击可能包括:使文件系统或数据库超载,接管完整的系统,客户端攻击,将攻击转发到后端系统或进行简单的破坏。
2. 点击劫持
这是一种恶意用户诱骗正常用户点击网页或不属于该站点的元素的攻击方式。这种攻击可能会导致用户在不经意间提供凭据或敏感信息、下载恶意软件、访问恶意网页、在线购买产品或转移资金。
3. XSS 攻击
这是一种将恶意脚本以浏览器端脚本的形式注入网页的攻击方式。网站上的缺陷使这些攻击广泛传播并得以成功。
4. SQL注入
这是一种通过输入字段把恶意代码注入到 SQL 语句中去破坏数据库的攻击方式。
5. 拒绝服务攻击( DoS 攻击)
这种攻击方式通过用流量轰炸服务器,使目标用户无法使用服务器或其资源。
6. 中间人攻击或会话劫持
这种攻击方式依靠拦截客户端与服务器之间的通信,以窃取密码、帐号或其他个人详细信息。
前端编码时要牢记的一些常见的准则
1.严格的用户输入(第一个攻击点)
用户输入在本质上应始终保持严格,以避免诸如 SQL 注入,点击劫持等漏洞。所以在将用户输入发送到后端之前,应该先对其进行验证或清理是非常重要的。
可以通过删除或替换上下文相关的危险字符来对数据进行清理,例如使用白名单并对输入数据进行转义。
但是,对于目前所有的可能性,清理和编码并不是一件容易的事,所以可以使用以下开源库:
-
DOMPurify
使用起来最简单,只需要有一个方法就可以清除用户的输入。它有自定义规则的选项,并且支持HTML5、SVG 和 MathML。 -
secure-filters
是 Salesforce 开发的一个库,其中提供了清理 HTML、JavaScript、内联 CSS 样式和其他上下文的方法。如果你想在某些地方使用用户输入的信息,例如生成 CSS 或 JavaScript 时,特别有用。
如果是文件上传,请务必检查文件类型并启用文件过滤器,并且只允许某些类型的文件上传。
2. 当心隐藏字段或存储在浏览器内存中的数据
如果你打算通过 input 的 type="hidden"
把敏感数据隐藏在页面中或把它添加到浏览器的 localStorage
,sessionStorage
,cookies
中,并且认为这是安全的,则需要重新考虑你的解决方案。
攻击者可以轻松的访问添加到浏览器中的所有内容。攻击者可以打开 dev tools 并更改所有内存变量。如果你根据 localStorage
、 sessionStorage
和 cookies
值隐藏了身份验证页面,会怎么样?
浏览器中有 ZapProxy 之类的工具,甚至是一些检查工具,它们可以在攻击者找到注入脚本的方法后把这些值暴露出来,然后攻击者就可以利用它们进一步的攻击。
因此要避免使用 type="hidden"
,以及避免把**、auth token 等过多地存储在浏览器的内存中。
3. 使用强大的内容安全策略(CSP)
永远不要信任服务器发送的“任何东西”,始终都要定义一个强大的 Content-Security-Policy HTTP 头,该标头仅允许某些受信任的内容在浏览器上执行或提供更多资源。
最好有一个白名单——允许的来源清单。即使攻击者注入了脚本,该脚本也不会与白名单匹配,更不会执行。
例如:
content-security-policy: script-src ‘self’ https://apis.xyz.com
在这里,应用程序仅信任来自 apis.xyz.com
和我们自己(self
)的脚本。对于其余的来源,在控制台中将会引发错误。
注意:强大的内容安全策略不能解决内联脚本执行的问题,因此 XSS 攻击仍然有效。
4. 启用 XSS 保护模式
如果攻击者以某种方式从用户输入中注入了恶意代码,我们可以通过 "X-XSS-Protection": "1; mode=block"
标头来指示浏览器阻止响应。
大多数现代浏览器默认情况下都启用了 XSS 保护模式,但仍建议你添加 X-XSS-Protection
标头。这有助于确保不支持 CSP 标头的旧版浏览器的安全性。
5. 避免典型的 XSS 错误
XSS 攻击通常可追溯到 DOM API 的 innerHTML
。例如:
document.querySelector('.tagline').innerHTML = nameFromQueryString
任何攻击者都可以用上面的代码行注入恶意代码。
考虑使用 textContent
而不是 innerHTML
,以防止完全生成 HTML 输出。如果你不生成 HTML,则无法插入 JavaScript,也许你会看到其中的内容,但什么事也不会发生。
请密切注意最新的受信任的类型规范,以防止借助 google 进行基于 DOM 的跨站点脚本攻击。
就 react.js 而言,应该对 dangerouslySetInnerHTML
保持谨慎的,并且可以产生与 innerHTML
类似的影响。
注意:切勿基于用户输入去设置 innerHTML
的值,而应该尽可能用 textContent
代替 innerHTML
。
同样,应正确设置 HTTP 响应头 Content-Type
和 X-Content-Type-Options
及其预期行为。例如不要把 JSON 数据编码为 text/HTML,以防止被意外执行。
6. 禁用 iframe 嵌入
禁用 iframe 可以使我们免受 clickjacking 攻击的影响。我们应始终在请求中使用 "X-Frame-Options":"DENY"
标头,以禁止在框架中渲染网站。
另外,我们可以用 frame-ancestors
CSP 指令,该指令可以更好地控制哪些家长可以将页面嵌入到 iframe 中。
7. 使用模棱两可的错误提示
诸如“你的密码不正确”之类的错误可能不仅对用户有用,对攻击者同样有帮助。他们可能会从这些错误中找出信息,从而帮助他们计划下一步的行动。
在处理帐户、电子邮件和 PII 时,我们应该尝试使用诸如“错误的登录信息”之类的模棱两可的错误提示。
8. 使用验证码
在面向公众的端点(登录、注册、联系)上使用验证码。 验证码是一种旨在区分人与机器人的系统,可以帮助阻止DoS(拒绝服务)攻击。
9. 始终设置 Referrer-Policy
每当我们用定位标记或导航到离开网站的链接时,请确保你使用标头策略 "Referrer-Policy": "no-referrer"
,或者在使用定位标记的情况下,设置 rel = noopener 或 noreferrer
。
如果不设置这些标头和相关性,则目标网站可以获得会话 token 和数据库 ID 之类的数据。
10. 对浏览器功能和 API 进行限制
与 CSP 中一样,受限域可以连接到网站,同样的原理也可以应用于浏览器功能和 API。我们可以添加一个 Feature-Policy
标头来拒绝对某些功能和 API 的访问。
提示:把所有你不用的功能设置为 none
。
11. 定期审核依赖性
定期运行 npm audit
以获取易受攻击软件包的列表,并对其进行升级避免安全问题。
现在 GitHub 对易受攻击的依赖项进行标记。还可以用 Snyk 来自动检查你的源代码并拉取 bump 版本。
12. 分隔你的应用程序
与后端一样,前端也可以使用微服务架构,其中单个应用被拆分为较小的自包含组件,每个组件都单独运行。
例如一个应用可以分为公共部分,身份验证部分和管理部分,每个部分都托管在单独的子域中,例如 https://public.example.com
, https://users.example.com
和 https://admin.example.com
。
这样可以确保减少客户端漏洞。
注意:适当的分隔还可以防止应用的公共部分出现 XSS 漏洞,从而防止它自动破坏用户信息。
13. 避免使用第三方服务
Google Analytics、Google Tag Manager、Intercom、Mixpanel 等第三方服务可能会使你的 Web 应用容易受到攻击。想一想假如这些第三方服务受到损害时会怎样。
制定强有力的 CSP 政策非常重要。 大多数第三方服务都有定义的 CSP 指令,所以请务必添加它们。
另外在添加脚本标签时,要确保在可能的情况下包含 integrity
属性。Subresource Integrity 功能可以验证脚本的加密哈希,并确保没有对其进行过篡改。
<script src= "https://example.com/example-framework.js" integrity= "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..." crossorigin= "anonymous" ></script>
慎重使用自动填充字段
存储在浏览器自动填充中的个人标识信息对于用户和攻击者都很方便。
攻击者可以通过添加第三方脚本,利用浏览器的内置自动填充功能提取电子邮件地址来构建跟踪标识符。他们可以用这些信息建立用户浏览历史记录配置文件,然后将其出售给坏人。
许多人甚至都不知道他们的浏览器自动填充功能到底存储了哪些信息。
提示:对敏感数据禁用自动填写表格功能。
上一篇: 小菜鸟
下一篇: TCP对端MSS值估算