我有一个提供纯 HTML 和 JS 文件的 nginx 服务器。
然后,js 代码调用各种 REST API 从 API 服务器获取/发布数据。
如果 nginx 收到对 /api/ 位置的请求,它会将请求转发到另一个处理所有 API 的服务器。这个 api 服务器是用 Ruby on Rails 构建的。
由于我所有的纯 HTML 页面都是由 nginx 直接提供的,因此在呈现它们时我不能有服务器端会话。
我可以做些什么来防止 CSRF 攻击?
我有一个提供纯 HTML 和 JS 文件的 nginx 服务器。
然后,js 代码调用各种 REST API 从 API 服务器获取/发布数据。
如果 nginx 收到对 /api/ 位置的请求,它会将请求转发到另一个处理所有 API 的服务器。这个 api 服务器是用 Ruby on Rails 构建的。
由于我所有的纯 HTML 页面都是由 nginx 直接提供的,因此在呈现它们时我不能有服务器端会话。
我可以做些什么来防止 CSRF 攻击?
CSRF 令牌的目的是要求攻击者从您的域中读取一个值以便发送请求。
因此,您可以在 API 中有一个单独的端点,它只返回一个 CSRF 表单令牌。
由于同源策略,攻击者将无法读取令牌(与他们无法从 HTML 源读取令牌的原因相同),因此您将是安全的。
这样做的缺点是需要额外的 HTTP 请求。
此外,请确保响应不是有效的 Javascript,否则攻击者可以将其作为<script>
标签运行并使用原型和属性技巧来读取值
由于您不能拥有服务器端会话,因此您需要一个不需要将令牌存储在服务器上的解决方案。相反,您需要做的是让您的 nginx 实现生成某种令牌,您将在对浏览器的响应中包含这些令牌。当攻击者代表另一个用户发送请求时,该值应出现在请求中未自动包含的位置(即应用程序生成的页面上的隐藏输入字段或元标记),并且还应存储在一个 cookie(显然会在 CSRF 攻击中自动发送)。当您的应用程序收到请求时,它可以验证这两个值是否相等。如果是这样,您可以将请求转发到 API。如果不是,您知道请求不是来自您的站点,您可以拒绝。
至少有两种方法可以做到这一点:
好: csrf_cookie: abc123 (cookie) csrf_param: abc123 (参数或标头)
更好:session_+_csrf_cookie:sessionid_val_--abc123 csrf_param:abc123(参数或标头)
第二种解决方案优于第一种的原因是第一种解决方案容易受到 cookie 强制的影响。第二个是安全的,因为如果 MITM 与您的会话 cookie 混淆,它无论如何都会使会话无效。使用第二种解决方案,您可以在代理到 API 之前简单地剥离令牌。
当然,所有这些都假设您使用的是 HTTPS。
安装 WAF(Web 应用程序防火墙)来检查 HTTP/HTTPS 流量,拒绝恶意请求,并且通常充当 Web 堆栈中的附加安全层。正确配置的 WAF 可以保护您的站点免受 SQLi、XSS、CSRF 和 DDoS 攻击,并提供暴力攻击缓解和零日威胁修补。
有一些可用于 nginx 的开源 WAF 选项。请参阅https://help.dreamhost.com/hc/en-us/articles/222784068-The-most-important-steps-to-take-to-make-an-nginx-server-more-secure
还有一个简单的 nginx 模块,它将引用者或源头与主机头进行比较。如果域名不匹配,则返回 HTTP 响应 403。见https://github.com/gartnera/nginx_csrf_prevent