繁体   English   中英

如何防止跨域ajax请求?

[英]How to prevent cross-domain ajax requests?

如何检测我的 php 脚本是否从另一个域调用,而另一个域正在非法使用我的脚本? 有没有办法防止这种情况?

更新

我在 SO 上找到了这个问题,但它仍然不安全,它可以被欺骗。

没有任何绝对万无一失的方法可以防止这种情况发生,因为任何 header 信息都可能被欺骗。 基于会话的令牌是另一种可能的解决方案,但在这种情况下,您的 javascript 是可公开访问的,因此任何想花一点时间的人都可以确定您的令牌系统如何工作并找出解决方法。

多种方法的组合将为您提供最广泛的保护。 您可以查找 header,使用和 .htaccess 文件,并使用令牌。 上述所有方法使得滥用 web 服务器变得更加困难 - 大多数滥用来自于试图找到一个容易利用的漏洞的人。 要记住的重要一点是,您不能因为部署了“最好的”保护而自满,或者因为您拥有太多似乎无法破解的保护层。 如果有人真的想要它足够糟糕并且有时间,他们会找到一种方法。 这些类型的预防措施实际上只是阻止懒惰、好奇和无知恶意的人。 有针对性的攻击是一个完全独立的安全 class,通常更集中在服务器级别的安全问题上。

示例 htaccess。 这不会是你放在根目录中的东西,而是放在一个子文件夹中,你的脚本永远不应该从地址栏中调用:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?_YOUR_DOMAIN_NAME_HERE.com [NC]
RewriteRule \.(php)$ - [NC,F,L]

查看这篇文章以获取有关使用令牌系统的信息: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet

您可以手动拒绝Origin header 与您的域名不匹配的每个请求。 但是,并非所有浏览器都发送Origin header。 在这些情况下,您可以回退到Referer [sic] header,对其进行解析并找出域名,然后如上所述进行比较。

一些 JavaScript 框架还为 AJAX 请求设置了X-Requested-With header。

这应该拒绝很大比例的用户(我估计> 95%)。 请注意,由于Same-Origin Policy ,向您的域发送 AJAX 请求的人唯一得到的是时间信息。

有点像 user3491125 建议的那样,您可以在进行调用的页面中设置一个 $_SESSION 并在调用的页面 Ajax 上检查它,如果有例如 $_SESSION['user'] 设置。

对于 user3491125 的回答,您可以尝试加密 session 令牌。 我有一个加密 function 可以添加基于用户端口 80 IP 的唯一密钥。 这不是万无一失的,但它确实使黑客更加困难。

function encryptString($string, $action, $baseIP = 'false', $extraKey = ''){
    global $flag;

    $encryptedIP = '';

    if($baseIP){
        $encryptedIP = encryptString(strip_tags(htmlentities($_SERVER['REMOTE_ADDR'])), 'encrypt', false);
    }

    $output = false;

    $encrypt_method = "AES-256-CBC";
    $secret_key = $flag['encrypt-key'].$encryptedIP.'-'.$extraKey;
    $secret_iv = $flag['encrypt-secret'].$encryptedIP.'-'.$extraKey;

    $key = hash('sha256', $secret_key);
    $iv = substr(hash('sha256', $secret_iv), 0, 16);

    $output;

    if($action == 'encrypt'){
        $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
        $output = base64_encode($output);
        $output = str_replace('=', '[equal]', $output);
    }else if($action == 'decrypt'){
        $setString = str_replace('[equal]', '=', $string);
        $output = openssl_decrypt(base64_decode($setString), $encrypt_method, $key, 0, $iv);
    }

    return $output;
}

我知道这是一篇旧文章,但目前有一种“万无一失”的方法可以避免这种情况,而且它非常简单......首先在ajax调用的页面中:

<?php
$token = sha1(rand(1000,9999)); 
$_SESSION['token'] = $token;
?>

然后在 ajax 脚本中

var formData = new FormData();
formData.append("token","<?php echo $token;?>");
        $.ajax({
            url: 'yourfile.php',
            type: 'POST',
            xhr: function() {
                var myXhr = $.ajaxSettings.xhr();
                return myXhr; 
            },
            success:function(data) {
                alert(data);
            },
            data: formData,
            cache: false,
            contentType: false,
            processData: false
        }); 

最后在将被调用的 php 页面中:

<?php
$token = $_POST['token'];
if($token === $_SESSION['token'] && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')
{
   //Perform your stuff here...
}
?>    

这不是一个可以解决的问题。 如果您创建了一个网站,则根据定义,您可以将其公开。
如果您希望您的数据是私密的,则需要某种登录方式。

如果没有登录/烦人的验证码,就不可能创建一个对用户开放但不对脚本开放的系统。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM