所以有一段时间我现在一直在尝试使用不同的AJAX方法将数据发送到服务器,该服务器将被处理并存储在MySQL数据库中。
AJAX请求命中api.php
的页面使用PHP的PDO预处理语句来保存数据,因此MySQL注入不是真正的问题,需要的密码或数据加密也由api.php
处理,这不是我在这里问的问题。我的问题更多地涉及如何确保数据在从客户端传输到服务器时是安全的。
我目前有(对于我在下面列出的登录示例):
login.php
和api.php
上使用这个例子)。api.php
的速率限制。api.php
内的数据库交互时准备语句。api.php
内的敏感数据(与问题无关)。最后,我的问题是:
我知道每个人都有不同的方法来处理他们的网站数据并传输这些数据。我也明白,无论你做什么,你永远不会受到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('<i class="fa fa-spinner fa-pulse fa-lg fa-fw"></i> 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"
});
}
答案 0 :(得分:53)
<强> 1。检查ORIGIN标题
作为specified by OWASP,这还不够,但建议:
虽然从您自己的浏览器中欺骗任何标头都是微不足道的,但在CSRF攻击中通常不可能这样做,除非是通过XSS漏洞。这就是为什么检查标题是CSRF防御中合理的第一步,但由于它们并不总是存在,所以它通常不被认为是足够的防御。
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标题
再次from OWASP:
如果Origin标头不存在,请验证Referer标头中的主机名是否与网站的原点匹配。检查引用是防止嵌入式网络设备上的CSRF的常用方法,因为它不需要每用户状态。这种CSRF缓解方法也常用于未经身份验证的请求[...]
使用HTTP_REFERER
在PHP中查看$_SERVER['HTTP_REFERER']
也非常简单,您可以用它来更新上面的代码。
要小心,检查始终需要非常具体:不要只检查 example.com 或 api.example.com 但是完整的 https://example.com 。为什么?因为您可以使用 api.example.com.hacker.com 等来源欺骗此检查。
<强> 2。生成CSRF令牌
简明扼要的answer specific to PHP has been given there,简而言之:
生成令牌:
session_start();
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
通过meta(如Github)在生成的视图中添加它:
<meta name="csrf-token" content="<?= $_SESSION['csrf_token'] ?>">
设置jQuery ajax调用以包含此标记:
$.ajaxSetup({
headers : {
'CsrfToken': $('meta[name="csrf-token"]').attr('content')
}
});
服务器端检查您的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。 Sanitize 验证用户输入。
您始终必须filter espace inputs和validate them。
<强> 4。保护您的服务器
<强> 5。永远不要相信用户输入
正如@ blue112所说,它是最基本的security principles之一。
答案 1 :(得分:1)
简短回答:你不能保护你的客户方。
答案很长:
你无法做任何事情让浏览器证明它实际上是你在客户端运行的javascript代码。 然后,明显要采取的行动是最简单的行动:永远不要信任用户输入。
这意味着,正如您开始所做的那样,使用会话,速率限制,数据验证,fail2ban(在一定数量的失败后禁止客户端IP)保护您的服务器端,日志监控......
答案 2 :(得分:0)
最好的方法仍然是服务器端保护,如果我是站点中的登录用户,我也可以检查我的元标记上的csrf标记并伪造脚本到服务器。所以肯定的赌注是服务器端验证