⭐️ 本文首发自 前端修罗场(点击加入),是
一个由 资深开发者 独立运行 的专业技术社区
,我专注Web 技术、Web3、区块链、答疑解惑、面试辅导以及职业发展
。博主创作的 《前端面试复习笔记》(点击订阅),广受好评,已帮助多位同学提升实力、拿到 offer。现在订阅,私聊博主即可获取一次 免费的模拟面试/简历指导服务,帮你评估知识点的掌握程度,获得更全面的学习指导意见!
目前的网络环境,共享的数据要比以往任何时候都多,对于用户而言,必须注意在使用应用程序中可能遇到的相关风险。
虽然 React 方便快捷,但这也使得它容易发生风险,并且很容易忽略安全问题。
尽管 React 的攻击数量比其他框架少,但它仍然不是完全安全的。 我们发现由于 React 与其他开源组件兼容并且没有强大的默认安全设置,因此它容易受到安全漏洞的影响。下面我们列举了一些 React 应用常见的安全问题。
由于 React 一直在更新和改进,因此我无法在此处创建详尽的漏洞列表。 但我会在这里讨论一些知名和常见的安全问题。
XSS 是一个严重的客户端漏洞。 攻击者能够将一些恶意代码添加到你的程序中,这些代码被解析并作为应用程序的一部分执行。 这会导致损害应用程序的功能和用户数据。
有两种跨站点脚本攻击类型:
反射型 XSS——攻击者使用恶意链接和浏览器处理的一些 JS 代码来访问和操纵页面内容、cookie 和其他重要的用户数据。
存储型 XSS——在这种攻击中,恶意内容存储在服务器上,并在用户请求存储数据时执行。 这会导致你的网页上出现你不想看到的内容。
React.js 应用程序中的另一个常见问题是授权不足或授权不佳。 这可能导致攻击者破解用户凭据并进行暴力攻击。
例如会话 ID 暴露在 URL 中、攻击者发现的简单且可预测的登录详细信息、凭据的未加密传输、注销后保持有效会话以及其他与会话相关的因素,都是与授权相关的各种风险,
此漏洞会暴露你的应用程序的数据库。 攻击者注入有害的 SQL 代码,允许他们在未经许可的情况下修改数据。
例如,黑客可以访问你应用的所有数据、创建虚假 ID,甚至获得管理员权限。
XXE
攻击是指攻击者针对将 XML 转换为可读代码所需的 XML 解析器。
恶意代码被注入解析器以收集敏感数据,甚至尝试进行 CSRF(跨站请求伪造)和 DDoS(分布式拒绝服务)攻击。
React 应用程序中有一个非常特殊的漏洞,称为 “zip slip”
,它涉及利用允许上传 zip
文件的功能进行攻击。
如果用于解压缩 zip 文件的存档不安全,则攻击者可以将上传的文件解压缩到指定目录之外,然后他们可以访问该文件。
这种威胁是一种普遍的风险,它使攻击者能够在你的应用程序的某些进程上执行任意命令。
这些随机命令很危险,因为它们可以更改你的配置文件或代码的任何部分。
目前,我们知道了可能出现的问题,接下来,让我们看看如何防范这些问题。
正如他们所说,一盎司的预防胜于一磅的治疗——因此遵循适当的协议并确保你的应用程序是安全的始终是一个好主意。
你可能不会考虑所有可能的漏洞,但你绝对可以通过减轻最常见的风险来使你的应用程序更安全。
以下是你应该遵循的一些最佳实践来保护你的 React 应用程序:
应用安全性的一个基本但重要的原则是确保服务器和客户端之间的连接是安全的。
构建应用程序时执行此操作的一种简单方法是确保 domain header
具有 realm
属性。 realm 包含有效用户列表,并在访问任何受限数据时提示输入用户名和密码。
以下是如何设置 security-realm
的示例:
<security-realm name="ApplicationRealm">
<authentication>
<local default-user="$local" allowed-users="comma-separated-list"/>
<properties path="application-users.properties"/>
authentication>
<authorization>
<properties path="application-roles.properties"/>
authorization>
security-realm>
如果可能,另一种简单有效的技术是使用多重身份验证。 这种身份验证方法可确保用户只有在提供两个或更多身份验证凭据以验证其身份后才能获得对应用程序重要部分的访问权限。
要遵循的另一个基本规则是,对于每次新登录,你应该始终使用安全的服务器会话管理器创建一个新会话 ID。
当你的 React 应用设置了基本的安全身份验证时,它有助于缓解 XSS 和损坏的身份验证问题。
任何 React 应用程序都需要 HTML 来呈现它,因此必须确保你的 HTML 代码不会受到攻击。 三种建设性的方法是:
当为任何 HTML 元素设置了“禁用”属性时,它变得不可变。 无法使用表单聚焦或提交该元素。
然后,你可以进行一些验证并仅在该验证为真时启用该元素。 这可以防止提交任何可能导致灾难性影响的恶意数据。
这是禁用按钮的示例代码片段:
const Component = React.createClass({
getInitialState() {
return {
submitting: true
}
},
handleSubmit() {
},
render() {
return (<div>
<button type="button" disabled={this.state.submitting} onClick={ this.handleSubmit }>Submit</button>
}
});
ReactDOM.render(
<Component />,
document.getElementById('container')
);
JavaScript XML (JSX) 是一种语法,可让你在 React 中编写 HTML。 它具有内置的自动转义功能,你可以使用它来保护你的应用程序。
如果你默认使用花括号 {}
绑定数据,那么 React 将自动转义不属于绑定数据的值。
这是一个例子:
return (<p style={{color: myAppColor}}>{myAppRating}</p>);
如果黑客试图在变量 myAppColor
中注入额外的代码,例如 color: purple, background-color: pink
,那么 JSX 解析器将检测到这个无效的 CSS 输入。 因此,额外的数据将被转义,攻击将被中和。
你的应用程序可能需要呈现动态 HTML 代码,例如用户提供的数据。 如果这是使用 “innerHTML”
完成的,那么这会使应用程序容易受到恶意数据的攻击。
React 有一个功能可以通知你这个潜在的漏洞,称为 dangerouslySetInnerHTML
属性。 使用它,你可以检查并确保在此属性存在时输入的数据来自受信任的来源。
return (<p dangerouslySetInnerHTML={{__html: myAppReview}}></p>);
你还可以使用 DOMPurify
等库来扫描用户输入并删除恶意内容。
// Import DOMPurify
const DOMPurify = require('dompurify')(window);
// 删除恶意内容
return (<p dangerouslySetInnerHTML={{__html: myAppReview}}></p>);
现在,假设攻击者在图像中添加了 “onerror”
代码,如下所示:
该应用程序<b>强大b>且<i>有趣。i>
<img src="reviewPic.png" onerror="alert('This app is not good!');" />
净化后的值将导致以下结果:
该应用程序<b>强大b>且<i>有趣。i>
<img src="reviewPic.png">
所有这些措施都可以保护你的 React 应用程序免受 XSS 和任意代码执行等攻击。
使用锚标记 和 URL 链接内容时,你需要非常小心攻击者添加以 JavaScript 为前缀的有效负载。
为避免基于 URL 的恶意脚本注入,请始终使用 HTTP 或 HTTPS 协议验证 URL。
function validateURL(url) {
const parsed = new URL(url)
return ['https:', 'http:'].includes(parsed.protocol)
}
<a href={validateURL(url) ? url : ''}>This is a link!</a>
保护 React 应用程序的另一种方法是使用允许列表/阻止列表方法。 白名单是指你拥有所有安全且允许访问的链接的列表,而黑名单则是拥有在请求访问时将被阻止的所有潜在威胁的列表。
很难跟踪所有可能的有害链接,因此一个好的做法是将已知站点列入白名单并阻止其他所有内容。
URL 验证有助于防止身份验证失败、XSS、任意代码执行和 SQL 注入。
在你的 React 应用程序中,始终使用最小权限原则。 这意味着必须允许每个用户和进程仅访问对其目的绝对必要的信息和资源。
在连接到应用程序的数据库时允许任何人更新、插入或删除是很危险的,因此为不同的用户分配正确的数据库角色非常重要。
除非至关重要,否则切勿将应用程序数据库的管理员权限授予任何人。 这使你的应用程序更安全,更不容易受到 SQL 注入攻击。
React API 的优点和缺点在于它们允许你的应用程序和其他服务之间的连接。 这些可以存储信息甚至执行命令。 这会将你的应用程序暴露给 XSS 和 SQL 注入。
针对此漏洞的一种强大的缓解技术是验证所有 API 函数的 API 模式。 此外,安排及时的模式验证并为所有交互使用 SSL/TLS 加密。
为了增加安全性,通过 API 传输数据时,请使用良性字符而不是 <
。
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace( /</g, '\\u003c')}
WAF 是一种应用程序过滤器,通过监控、分析和过滤双向流量来检测和阻止恶意内容。
你可以通过三种方式实现 Web 应用程序防火墙:
WAF 基于签名的过滤在对抗 SQL 注入、XSS、任意代码执行和 zip 滑动方面非常有效。
在你的 React 应用程序中,你应该始终遵循正确的文件管理实践,以避免 zip slip 和其他类似风险。
你的 React 应用程序很有可能使用 JSON 来设置应用程序的初始状态。
这可能具有潜在危险,因为 JSON.stringify()
是一个将任何数据转换为字符串而不检测恶意值的函数。 攻击者可以通过注入可以修改有效数据的 JS 对象来操纵用户名和密码等数据。
<script>window.__STATE__ = ${JSON.stringify({ data })}script>
你可以使用 serialize-javascript
NPM 模块来转义呈现的 JSON,也可以使用复杂的 JSON 格式来避免序列化。 但防止任何意外的最好方法是从序列化表单中省略机密数据。
在创建 React 应用程序时,你必须考虑许多潜在威胁。 如果没有适当的安全性,你的应用程序可能会成为网络攻击的受害者,这可能导致经济损失、浪费时间、违反信任和法律问题。
随着每天都有新的威胁出现,攻击者利用越来越多的漏洞,使你的 React 应用程序安全可能非常复杂和困难。
你可以聘请专门从事安全性的 React 开发人员,也可以将开发外包给专门开发 React 应用程序的软件开发公司。 总之,在安全方面,请确保你身边有专家!