2012-02-22 4 views
21

Существует ли «безопасный» способ проверить, применяется ли одна и та же политика происхождения к URL-адресу, прежде чем приступить к использованию методов ajax? Вот что у меня есть:Проверьте, применяется ли та же политика происхождения

function testSameOrigin(url) { 

    var loc = window.location, 
     a = document.createElement('a'); 

    a.href = url; 

    return a.hostname == loc.hostname && 
      a.port == loc.port && 
      a.protocol == loc.protocol; 
} 

Этот вид работ, но это своего рода ручной догадка, основанная на wikipedia article. Есть ли лучший способ предварительной проверки надбавки за кросс-домен? jQuery подходит для использования.

+0

Если вы выполняете кросс-доменный запрос, он сработает с 'readystate = 4' и' statuscode = 0', что аналогично прерванному запросу. Так как вам все равно нужно защищать от прерванных запросов, зачем вам нужна эта проверка? Я чувствую, что эта мера безопасности применяется снаружи, вы не контролируете ее, поэтому любая проверка изнутри среды по определению неверна. Поэтому я не думаю, что вы должны когда-либо проверять это, просто пропустите запрос. – Halcyon

ответ

8

Интересный вопрос! Я искал вокруг и не мог найти ничего, кроме того, что вы разместили, но мне это показалось, когда я возился с некоторым тестовым кодом. Если вы просто хотите простой способ проверить URL-адрес без запроса, я бы сделал это так, как вы это делаете. Если вы не заботитесь о том, чтобы запрос, чтобы проверить, вы можете попробовать это:

сделать простой запрос Аякса любой URL вы хотите:

var ajaxRequest = $.ajax({ 
    url: 'http://www.google.com', 
    async: false 
}); 

который возвращает jqXHR объект, который затем можно проверьте:

ajaxRequest.isRejected(); // or... 
ajaxRequest.isResolved(); 

Теперь, единственная проблема состоит в том, что isRejected() будет вычисляться true для каждого отдельного случая, когда страница не загружается (то есть 404 не найден, и т.д.), но вы можете проверить статус код с:

ajaxRequest.status; 

Похоже, что выше линия будет возвращать 0 при попытке сломать ту же политику происхождения, но он возвращает соответствующий код ошибки (опять же, то есть 404) и в других случаях.

Так завернуть, может быть, вы могли бы попытаться сделать что-то вроде:

function testSameOrigin(testUrl) { 

    var ajaxRequest = $.ajax({ 
    url: testUrl, 
    async: false 
    }); 

    return ajaxRequest.isRejected() && ajaxRequest.status === 0; 
} 

не окончательный ответ любыми средствами, но я надеюсь, что это поможет вам понять, что вы ищете!

+0

Да, это интересный подход. В моем первоначальном случае я хотел избавиться от неприятных ошибок консоли, которые вы получаете при выполнении отклоненного вызова ajax, пытаясь «проверить» URL. Я также недавно обнаружил, что выполнение запросов ajax в локальном файле (файл: протокол) также прерывается каждый раз. Итак, это еще один случай, чтобы проверить ... – David

+0

Вы можете использовать ajax для локальных файлов, установив флаг 'isLocal' в' true' http://api.jquery.com/jQuery.ajax/# jQuery-ajax-settings – Steve

0

Другой способ выполнения междоменного скрипта - использовать JSON-P. Вы также можете прочитать это article. В противном случае междоменная сценария не допускается одной политикой происхождения.

+0

Я не уверен, почему все ответы касаются того, как сделать или не делать кросс-браузерные запросы ajax, что совсем не то, что я прошу ... Нужно ли мне быть более ясным? – David

10

Есть ли «безопасный» способ проверить, применяется ли одна и та же политика происхождения к URL-адресу до фактического использования методов ajax? Вот что у меня есть:

function testSameOrigin(url) { 

    var loc = window.location, 
     a = document.createElement('a'); 

    a.href = url; 

    return a.hostname == loc.hostname && 
      a.port == loc.port && 
      a.protocol == loc.protocol; 
} 

Это безопасный и надежный способ сделать это, при условии, что вы делаете (или, вернее, не делать) некоторые вещи.

Этот вид работ, но это своего рода руководство, основанное на статье в википедии.

Это должно полностью работать в соответствии с «нормальными» обстоятельствами. Его нужно будет изменить, если вы планируете использовать cross-domain scripting.

Если вы изменяете document.domain в своих сценариях, например, с примера "foo.example.com" и "bar.example.com".ком»ваша testSameOrigin функция будет возвращать false для„http://example.com“, где на самом деле он должен вернуть true.

Если вы планируете изменения document.domain, вы можете просто добавить добавить проверку, что в сценарии.

Если вы планируете использовать CORS (см. Ссылку выше), чтобы разрешить междоменную связь, она также вернет ложный отрицательный результат. Но если вы используете CORS, у вас будет список доменов, с которыми вы можете общаться, и вы может также добавить этот список к этой функции.

Есть ли лучший способ предварительной проверки надбавки за кросс-домен? jQuery подходит для использования.

Вероятно, нет, хотя это может быть стоит упомянуть то, что вы видите в консоли от ответа Стива может быть «дилемма наблюдателя» ... Эти ошибки выглядят как они в результате консоли пытаются осмотрят другое окно, не обязательно из сценария.

Предполагая, что вы не возитесь с document.domain или используете CORS, ваше исходное решение, вероятно, лучше, так как не нужно делать дополнительный запрос, чтобы определить, доступен ли сервер или нет. Даже если вы делаете некоторые междоменные скрипты, изменение функции, которую вы теперь можете разместить, вероятно, будет вашим лучшим выбором.

+1

, в то время как это хороший способ проверить запросы CORS, которые он разбивает на IE7, в то время как сгенерированный якорь не возвращает никакой информации о ссылке, например, оценивая ссылку, такую ​​как '' в IE7 it вернет 'a.href =>" main.html "' 'a.hostname =>" "и т. д. Я все еще пытаюсь выяснить, как с этим справиться в IE7 tho. но не нашел хорошего решения. так как он никогда не будет создавать полный href. – zanona

+0

Что вы хотите добавить в документ document.domain? Будет ли просто заменяться 'loc.hostname' на' document.domain' правильно? –

+0

@BT 'a.hostname' все равно будет« foo.example.com », а' document.domain' будет просто «example.com». Это должно быть проверка специального случая, то есть, если вы знаете, что вы переписываете как document.domain 'на example.com, так и проверку имени хоста, было бы что-то вроде' a.hostname == loc.hostname || a.hostname == "foo.example.com" ' –

0

Строительство от ответа Дагг Nabbit, это кажется немного более полным:

function sameOrigin(url) { 
    var loc = window.location, a = document.createElement('a') 
    a.href = url 

    return a.hostname === loc.hostname && 
      a.port === loc.port && 
      a.protocol === loc.protocol && 
      loc.protocol !== 'file:' 
} 

Предостережения я могу думать:

  • не принимает во внимание document.domain
  • Безразлично не учитывается CORS
  • Не работает в IE7 (как упоминалось zanona)
  • не работает в странных условиях (как андроид), где вы можете доступ произвольных file:// пути протокола (кто-то пожалуйста, проверьте это, информация о андроиде может быть устаревшим https://security.stackexchange.com/questions/25138/same-origin-policy-for-file-urls-in-android-browser)
1

Попробуйте это решение, а также.

function csrfSafeMethod(method) { 
    // these HTTP methods do not require CSRF protection 
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 
} 

function sameOrigin(url) { 
    // test that a given url is a same-origin URL 
    // url could be relative or scheme relative or absolute 
    var host = window.document.location.host; // host + port 
    var protocol = window.document.location.protocol; 
    var srOrigin = '//' + host; 
    var origin = protocol + srOrigin; 
    // Allow absolute or scheme relative URLs to same origin 
    return (url === origin || url.slice(0, origin.length + 1) === origin + '/') || 
    (url === srOrigin || url.slice(0, srOrigin.length + 1) === srOrigin + '/') || 
    // or any other URL that isn't scheme relative or absolute i.e relative. 
    !(/^(\/\/|http:|https:).*/.test(url)); 
} 

// if you want to check before you make a call 
if (!csrfSafeMethod(data.type) && sameOrigin(data.url)) { 
    // ... 
} 

// or if you want to set csrf token 
$.ajax({ 
    beforeSend: function (xhr, settings) { 
    if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { 
     xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken")); 
    } 
    } 
}); 
Смежные вопросы