2012-02-22 10 views
21

¿Existe alguna manera "segura" de verificar si la misma política de origen se aplica a una URL antes de intentar realmente utilizar los métodos ajax? Aquí es lo que tengo:Compruebe si se aplica la misma política de origen

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; 
} 

Este tipo de obras, pero es una especie de manual de conjetura basada en la wikipedia article. ¿Hay una mejor manera de verificar previamente la asignación de dominio cruzado? jQuery está bien para usar.

+0

Si realiza una solicitud de dominio cruzado, fallará con 'readystate = 4' y' statuscode = 0', que es similar a una solicitud cancelada. Ya que necesita protegerse contra las solicitudes abortadas de todos modos, ¿por qué necesitaría este cheque? Siento que esta medida de seguridad se aplica desde el exterior, usted no tiene control sobre ella, por lo que cualquier verificación desde el entorno es, por definición, incorrecta. Así que no creo que deba verificarlo, solo deje que la solicitud falle. – Halcyon

Respuesta

8

¡Pregunta interesante! Busqué por todas partes y no pude encontrar nada más que lo que publicaste, pero me encontré con esto cuando estaba jugando con algún código de prueba. Si solo quieres una forma simple de probar una URL sin hacer una solicitud, lo haría de la manera que lo estás haciendo. Si no se preocupan por hacer una petición para probar, puede probar esto:

hacer un simple petición AJAX a cualquier URL que desee:

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

que devuelve un objeto jqXHR, que luego se puede comprobar:

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

Ahora, el único problema con esto es que isRejected() evaluará a true para todos los casos en que la página no se carga (es decir, 404 no encontrado, etc.), pero se puede comprobar el estado código con:

ajaxRequest.status; 

Parece que la línea anterior devolverá 0 cuando se intenta romper la política del mismo origen, pero devolverá el código de error correspondiente (de nuevo, es decir, 404) en otros casos.

Así que para concluir, tal vez usted podría intentar hacer algo como:

function testSameOrigin(testUrl) { 

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

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

No es una respuesta definitiva por cualquier medio, pero espero que le ayuda a conocer lo que está buscando!

+0

Sí, ese es un enfoque interesante. En mi caso original, quería deshacerme de los desagradables errores de consola que recibía cuando hacía la llamada ajax rechazada tratando de "validar" la URL. También descubrí hace poco que hacer una solicitud ajax en un archivo local (el archivo: protocolo) también falla siempre. Así que ese es otro caso para verificar ... – David

+0

Puede usar ajax para archivos locales estableciendo el indicador 'isLocal' en' true' http://api.jquery.com/jQuery.ajax/# jQuery-ajax-settings – Steve

0

Otra forma de ejecutar secuencias de comandos de dominios cruzados es usando JSON-P. También puede leer este article. De lo contrario, las secuencias de comandos de dominio cruzado no están permitidas por la misma política de origen.

+0

No estoy seguro de por qué todas las respuestas se refieren a cómo hacer o no las solicitudes de ajax de navegadores cruzados, eso no es para nada lo que estoy preguntando ... ¿Debo ser más claro? – David

10

¿Existe alguna manera "segura" de verificar si la misma política de origen se aplica a una URL antes de intentar realmente utilizar los métodos ajax? Aquí es lo que tengo:

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; 
} 

Esta es una manera segura y fiable de hacerlo, siempre y cuando usted está haciendo (o más bien no hacer) ciertas cosas.

Este tipo de trabajo funciona, pero es una suposición manual basada en el artículo de la wikipedia.

Esto debería funcionar en las circunstancias "normales". Deberá modificarse si planea usar cross-domain scripting.

Si modifica document.domain en sus scripts, por ejemplo de "foo.example.com" y "bar.example.com" a "ejemplo.com" su función testSameOrigin volvería false para 'http://example.com', cuando en realidad debería devolver true.

Si está pensando en modificar document.domain, puede agregar simplemente añadir un cheque por que en el script.

Si está planeando usar CORS (consulte el enlace anterior) para permitir la comunicación entre dominios, también devolverá un falso negativo. Pero si está utilizando CORS, tendrá una lista de dominios con los que se puede comunicar, y usted puede agregar esa lista a esta función también.

¿Hay una mejor manera de verificar previamente la asignación de dominio cruzado? jQuery está bien para usar.

Probablemente no

, aunque puede ser vale la pena mencionar que lo que está viendo en la consola de la respuesta de Steve podría ser el "dilema del observador" ... Esos errores parecen que son el resultado de la consola tratando de inspeccionar el otra ventana, no necesariamente desde la secuencia de comandos.

Suponiendo que no se está metiendo con document.domain o usando CORS, su solución original es probablemente mejor, ya que no necesita hacer una solicitud adicional para determinar si el servidor está disponible o no. Incluso si está haciendo algunas secuencias de comandos de dominios cruzados, la mejor opción es modificar la función que tiene ahora para acomodarlo.

+1

Si bien esta es una buena forma de comprobar las solicitudes CORS, se rompe en IE7, mientras que el anclaje generado no arrojará información sobre el enlace, por ejemplo evaluando un enlace como '' en IE7 devolverá 'a.href =>" main.html "' 'a.hostname =>" "' etc. Todavía estoy intentando descubrir cómo manejar esto en IE7 aunque. pero no pudo encontrar ninguna buena solución. ya que nunca creará el href completo. – zanona

+0

¿Qué comprobación de document.domain agregarías? ¿Simplemente sería correcto reemplazar 'loc.hostname' con' document.domain'? –

+0

@BT 'a.hostname' seguiría siendo" foo.example.com "y' document.domain' sería simplemente "example.com". Tendría que ser una verificación de caso especial, es decir, si sabe que está reescribiendo ambos 'document.domain's a" example.com ", la comprobación del nombre de host sería algo así como' a.hostname == loc.hostname || a.hostname == "foo.example.com" ' –

0

edificio fuera de la respuesta de Dagg Nabbit, esto parece un poco más completa:

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:' 
} 

Advertencias puedo pensar en:

1

Pruebe esta solución también.

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")); 
    } 
    } 
}); 
Cuestiones relacionadas