2009-12-23 76 views
43

我使用我的PHP後端通過檢查$_SERVER['HTTP_X_REQUESTED_WITH']中的值來檢測AJAX請求。在PHP中檢測Ajax並確保請求來自我自己的網站

這給了我一個可靠的檢測,確保請求是利用AJAX技術。

如何確保請求來自我自己的域,而不是外部域/機器人?

www.example.com/ajax?true可以允許任何人進行AJAX調用並剪切信息。

我可以爲每個進入我的網站的人正常開會,然後允許AJAX呼叫......但那也可能是假的。

這些事情現在有沒有關係?

回答

31

讓你控制器

  • 生成會話訪問令牌
  • 商店後面的比較

在你看來

  • 聲明訪問令牌作爲JS變量
  • 每個請求發送令牌

回到你的控制器

  • 驗證HTTP_X_REQUESTED_WITH
  • 驗證令牌

檢查這些安全guidelines from OpenAjax
另外,請閱讀有關codinghorror.com Annie的文章。

+3

+1由於基於瀏覽器的AJAX請求隨每個請求一起發送cookie,因此您只需在每個頁面上添加一個令牌檢查。 – Xeoncross 2009-12-23 17:12:47

+7

這不會阻止機器人直接打開API。它可以像JavaScript應用程序一樣獲取訪問令牌。 – Quentin 2014-09-17 09:18:19

0

檢查$_SERVER['HTTP_REFERER']。這在很多情況下都能正常工作,但不應該將它們混淆成完全安全的解決方案。

+1

這會給你你需要的東西,但不可靠,因爲瀏覽器可以把它喜歡的東西放在這裏。假冒很容易,所以價值不可能真正值得信賴。從根本上說,即使您向頁面發出令牌並使您的ajax請求將令牌傳回給您,您也無法保證請求來自任何地方。真的,你必須問自己,這是否重要? – 2009-12-23 16:56:29

+0

@Jonathan Sampson - 我可以像BurpSuite那樣捕獲請求並更改HTTP_REFERER ...所以我不認爲這是解決方案。我也可以用捲曲的腳本來做。 – 2009-12-23 16:56:37

23

您可以檢查HTTP_REFERRER,但不是所有瀏覽器都設置它。最好的方法是在JavaScript端發送ajax調用的包裝器,它將document.cookie的一部分發送回服務器 - 只有你的域可以訪問cookie。您可以將請求標頭中的cookie與php中的AJAX調用中的cookie進行比較。

作爲迴應,「它甚至很重要,這些天」 - 是的,它的確如此! Read this

+2

我不確定這種方法會通過默默無聞的方式完成除安全以外的任何操作。製作一個Web請求是微不足道的,這是一個Ajax請求。檢查Javascript包裝並添加它將添加的任何內容稍微不重要。所有這些都是模擬會話令牌。 – zombat 2009-12-23 17:27:09

+1

我猜如果他們沒有使用Javascript,它可能會讓機器人停留在海灣。但它本身不會提出請求*安全*。 – zombat 2009-12-23 17:29:43

+0

此方法需要訪問會話cookie。如果機器人可以訪問會話cookie,那麼是的,該網站是不安全的。但是你也有比XSRF更大的問題! – Annie 2009-12-23 17:50:35

3

大衛·沃爾什具有良好的solution

/* decide what the content should be up here .... */ 
$content = get_content(); //generic function; 

/* AJAX check */ 
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { 
    /* special ajax here */ 
    die($content); 
} 

/* not ajax, do more.... */ 
+1

這與保護請求無關。 – Xeoncross 2009-12-23 17:13:29

+0

任何人都可以將HTTP標頭添加到請求中。 – 2014-05-15 20:10:09

2

真的,最安全的方法就是按照您的建議使用服務器端會話,因爲這些會話不能像Cookie那樣製作。當然,某人仍然可以劫持會話ID,但是如果您還將用戶的IP地址存儲在他們的會話中並在每個請求中檢查它,那麼可以清除很多劫持。只有在同一局域網或代理上的人才能劫持它。

提到的任何其他方法 - cookies,javascript,http referer - 取決於客戶端數據,這些數據是不安全的,應始終懷疑是僞造,僞造,劫持和惡意構建。

+0

同意,並且可以改變會話生成的方式,以便它們更安全。 – Quamis 2009-12-24 13:13:12

6

關於你的最後一個問題:「在這些日子裏,它甚至很重要嗎?」 這是個案的問題。如果ajax請求正在做一些不需要安全性的事情(例如,加載最新的股票報價),那麼它對於恕我直言並不重要。如果請求正在加載應該保護的信息(例如,返回標識信息或在服務器上執行某些操作),那麼您應該將其視爲等待。

我個人不使用服務器變量來知道何時是ajax請求。相反,我只是添加一個查詢參數給ajax調用(例如http://domain.com/?ajax=true)。如果我需要保護ajax調用,那麼我會使用與保護常規頁面請求(使用客戶端和服務器)相同的方法。正如Lucas Oman指出的那樣,客戶端的任何東西都可能是僞造的。底線不相信任何請求,即使您認爲它來自您的網站或數據庫。始終遵循口頭禪「過濾器輸入 - 退出輸出」。

+1

是的,是的,是的。吉姆說話有道理。聽他的。 – Quentin 2009-12-23 17:54:34

+0

這是最好的答案。您永遠無法確定向您的網站發送請求的來源。即使請求已通過身份驗證,用戶也可能正在使用bot和有效憑據,甚至只是將其cookie從瀏覽器中拉出。 – frostymarvelous 2015-11-11 12:58:45

1

使用POST會話安全要求:

網頁內(如的index.php),我們需要存儲的SessionID

<?php 
// Create Session 
$session = session_id(); 
if(empty($session)) session_start(); 
?> 
<head> 
... 
<script type="text/javascript"> 
    sid = '<?php echo session_id(); ?>'; 
</script> 
<script type="text/javascript" src="ajaxrequest.js"></script> 
... 
</head> 

Ajax請求(ajaxrequest.js)

/* simple getAjax function 
* @param $url  request url 
* @param $param  parameter (dont use ?) 
* @param callback function on success 
*/ 
var spinnerid = '#spinner'; // Spinner as long ajax requests running 
$(document).ajaxStart(function() { $(spinnerid).show(); }); 
$(document).ajaxStop(function() { $(spinnerid).hide(); }); 
function getAjax(url, param, callback) { 
    var data = null; 
    url += "?sid=" + sid + "&" + param; 
    $.ajax({ 
     url: url, 
     method: "POST", // uncomment to use GET, POST is secured by session 
     cache: false, 
     async: true, 
     success : function(data){ 
     callback(data); 
    }, 
} 

getAjax('http://domain.com/', 'data=foo', function(data) { 
// do stuf with data 
var jsonobj = eval("(" + data + ")"); 
var data = jsonobj[0][ 'data' ]; 
}); 

負責任的php方面:

if(isset($_GET['sid'])) $client_sid = $_GET['sid']; 

if(session_id() == null) session_start(); 

if(session_id() != $client_sid) { 
    // noID or wrongID, redirect to mainindex 
    ignore_user_abort(true); 
    header("HTTP/1.1 403 Forbidden"); 
    header("Connection: close", true); 
    exit; 
} else { 

    // get data 
    if(isset($_GET['data'])) { 
     $data = $_GET['data']; 
    } else if(isset($_POST['data'])) { 
     $data = $_POST['data']; 
    } else { 
     $data = null; 
    } 

    // do stuff with data 

    // return data as json 
    $resp[0]['data'] = $data; 
    print_r(json_encode($resp)); 
} 
+0

出於安全原因,我不會使用會話ID。建議爲每個請求生成一個隨機令牌,保存在會話中。閱讀此:https://docs.phalconphp.com/en/latest/reference/security.html#cross-site-request-forgery-csrf-protection – Yossi 2016-02-13 23:01:33

+0

雖然這將工作,因爲ajax發佈數據(不使用get) ,任何人都可以通過查看JavaScript來看到這些值。他們可以複製數據,創建自己的表單並將其發佈到同一位置。對$ _SERVER ['HTTP_REFERER']的檢查將有助於防止這種情況,就像檢查數據是否通過ajax發佈一樣,但它仍然不完全安全。有沒有更好的辦法? – james 2017-09-26 10:41:39