如何防止跨域ajax请求?

时间:2011-06-14 17:58:12

标签: php security cross-domain

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

更新

我在SO上发现this问题,但它仍然不安全,可能会被欺骗。

6 个答案:

答案 0 :(得分:4)

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

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

示例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

答案 1 :(得分:1)

您可以手动拒绝Origin标头与您的域名不匹配的每个请求。但是,并非所有浏览器都会发送Origin标头。在这些情况下,您可以回退到Referer [sic]标题,解析它并查找域名,并按上述方式进行比较。

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

对于user3491125的答案,您可以尝试加密会话令牌。我有一个加密功能,可以基于用户端口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;
}

答案 4 :(得分:-3)

这不是一个可以解决的问题。如果您创建一个网站,您可以根据定义公开提供该网站 如果您希望数据是私有的,则需要进行某种登录。

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

答案 5 :(得分:-3)

我知道这是一篇很老的帖子,但目前 THERE IS 是一种“万无一失”的方法来避免这种情况,它就像地狱一样简单...... 首先在将进行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...
}
?>