如何使用PHP和jQuery发送安全的AJAX请求

问题

所以有一段时间我一直在尝试使用不同的AJAX方法将数据发送到服务器,该服务器将被处理并存储在MySQL数据库中。

AJAX请求命中api.php的页面使用PHP的PDO预处理语句来保存数据,因此MySQL注入并不是真正的问题,需要加密的密码或数据也由api.php处理。我在这里问的是什么。 我的问题更多地涉及如何确保数据在从客户端传输到服务器时是安全的。

方法

我目前有(对于我在下面列出的登录示例):

  • 域上运行的SSL证书/ HTTPS。
  • 某些AJAX请求(显然不是这个登录请求示例,因为没有会话开始)只有在PHP会话在整个站点上有效时才有效(在本例中用于login.phpapi.php )。
  • 访问函数时对api.php速率限制。
  • PHP PDO在与api.php的数据库交互时准备语句。
  • 加密api.php敏感数据(与问题无关)。

问题

最后,我的问题是:

  1. 这种使用异步HTTP(Ajax)请求的方法是否足够安全,而不仅仅是将数据提交到PHP页面并重定向? (这种方式改善了用户的体验)。
  2. 如何检查我的用户发送的数据是否未被篡改?
  3. 我是否合理地保护用户的数据,如果没有,我还能做什么?

这个例子

我了解每个人都有不同的方法来处理他们的网站数据和传输数据。 我也明白,无论你做什么,你永远不会受到100%的保护,因为你的系统可能存在漏洞和方法,你无法解释。 我正在寻找有关安全发送数据的一般方法的反馈/改进,而不是批评下面的具体代码,因为它只是一个例子。 但任何建设性的答案都是受欢迎的。 感谢您花时间阅读/回答。

 function loginUser() { var process = "loginUser"; var data = $("form").serializeArray(); data[1].value = SHA512(data[1].value); // sha then encrypt on api.php page data = JSON.stringify(data); $("#loginButton").html(' Login'); $.ajax({ type: "POST", url: "api.php", data: {"process": process, "data": data}, success: function(data) { if (data.response.state == "success") { // if api.php returns success, redirect to homepage } else { // if api.php returns failure, display error } }, error: function(jqXHR, textStatus, errorThrown, data) { // error handling }, dataType: "json" }); } 

1.检查ORIGIN标题

正如OWASP所指出的 ,这还不够,但建议:

虽然从您自己的浏览器中欺骗任何标头是微不足道的,但在CSRF攻击中通常不可能这样做,除非是通过XSS漏洞。 这就是为什么检查标题是CSRF防御中合理的第一步,但由于它们并不总是存在,因此它通常不被认为是足够的防御。

并由Mozilla :

Origin标头被认为有助于JSON数据窃取和CSRF攻击。 Origin提供的信息 – 一些上下文请求创建信息 – 应该向Web服务器提供有关请求可信度的提示[…]

检查HTTP_ORIGIN标头可写为:

 header('Content-Type: application/json'); if (isset($_SERVER['HTTP_ORIGIN'])) { $address = 'http://' . $_SERVER['SERVER_NAME']; if (strpos($address, $_SERVER['HTTP_ORIGIN']) !== 0) { exit(json_encode([ 'error' => 'Invalid Origin header: ' . $_SERVER['HTTP_ORIGIN'] ])); } } else { exit(json_encode(['error' => 'No Origin header'])); } 

1.(bis)检查REFERER标题

再次来自OWASP :

如果Origin标头不存在 ,请validationReferer标头中的主机名是否与站点的原点匹配。 检查引用是防止嵌入式网络设备上的CSRF的常用方法,因为它不需要每用户状态。这种CSRF缓解方法也常用于未经身份validation的请求[…]

使用$_SERVER['HTTP_REFERER']在PHP中检查HTTP_REFERER也非常简单,您只需用它来更新上面的代码即可。


小心的检查总是需要非常具体:不要只检查example.comapi.example.com,而是检查完整的https://example.com 。 为什么? 因为您可以使用api.example.com.hacker.com等来源欺骗此检查。


2.生成CSRF令牌

简而言之, 那里给出了一个特别针对PHP的解释清楚的答案 :

  1. 生成令牌:

     session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } 
  2. 通过meta(如Github)将其添加到生成的视图中:

      
  3. 设置jQuery ajax调用以包含此标记:

     $.ajaxSetup({ headers : { 'CsrfToken': $('meta[name="csrf-token"]').attr('content') } }); 
  4. 服务器端检查您的AJAX请求:

     session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } header('Content-Type: application/json'); $headers = apache_request_headers(); if (isset($headers['CsrfToken'])) { if ($headers['CsrfToken'] !== $_SESSION['csrf_token']) { exit(json_encode(['error' => 'Wrong CSRF token.'])); } } else { exit(json_encode(['error' => 'No CSRF token.'])); } 

大多数PHP框架都有自己的CSRF实现,或多或少都有相同的原则。


3。 消毒 validation用户输入。

你永远都必须 过滤 espace输入并validation它们 。


4.保护您的服务器

  • 限制您的请求数量 。
  • 尽可能使用https 。
  • 阻止错误查询 。
  • 保护POST请求 。

5.永远不要相信用户输入

正如@ blue112所说,它是最基本的安全原则之一 。

在此处输入图像描述

简短回答:你不能保护你的客户方。

答案很长:

  • 使用AJAX与使用表单发布数据一样安全。
  • 使用HTTPS可防止中间人看到您的用户数据,因此用户发送的实际数据是安全的。

您无法做任何事情让浏览器certificate它实际上是您在客户端运行的javascript代码。 然后,采取的明显行动是最简单的: 永远不要信任用户输入。

这意味着,正如您开始所做的那样,使用会话,速率限制,数据validation,fail2ban(在一定数量的失败后禁止客户端IP)来保护您的服务器端,日志监控……

最好的方法仍然是服务器端保护,如果我是站点中的登录用户,我还可以检查我的元标记上的csrf标记并伪造脚本到服务器。 所以肯定的赌注是服务器端validation