2016-05-30 22 views
4

ich eine Login-Seite haben https://example.com/login#destination wo destination die Ziel-URL ist der Benutzer versuchte, zu navigieren, wenn sie erforderlich waren eingeloggt sein.
(dh https://example.com/destination)URL ist relativ, bevor sie über JavaScripts location.replace Navigation()

die JavaScript ich dachte über die Verwendung war

function onSuccessfulLogin() { 
    location.replace(location.hash.substring(1) || 'default') 
} 
  • Dies in einer XSS-Schwachstelle führen würde, von einem Angreifer die Bereitstellung der Verbindung
    https://example.com/login#javascript:..

  • Auch ich muss nach der Anmeldung die Navigation zu einer Lookalike-Site verhindern.
    https://example.com/login#https://looks-like-example.com
    oder https://example.com/login#//looks-like-example.com

Wie kann ich einstellen onSuccessfulLogin die URL in dem Hash-# Abschnitt vorgesehen, um sicherzustellen, ist eine relative URL, und nicht an dem Start mit javascript:, https:, // oder anderem absoluten Navigationsschema?

Ein Gedanke ist es, die URL zu bewerten und festzustellen, ob location.origin vor der Navigation unverändert bleibt. Können Sie   vorschlagen, wie Sie dies tun, oder einen besseren Ansatz?

+0

erster Gedanke, der mir einfällt, ist eine Ajax HEAD Anfrage ... dann im Erfolg umleiten – charlietfl

+0

Es gibt nicht genug Daten, um eine vollständige Lösung zu erarbeiten, aber um die Dinge ein bisschen einfacher und mehr coder freundlich zu machen, könnte ich leih dir meinen JavaScript Location Konstruktor, der auf folgende Weise benutzt werden kann. 'var loc = neue Lok (sURL); loc = loc.hash.split ("#") [1]; if (/javascript|http/i.test (loc.protocol)) {loc.hash = Standard; location = loc.href}; aber ich brauche noch eine bessere Klärung der Situation. –

+0

@GeorgeBailey, natürlich ist es nicht - aber wenn Sie es nicht gut gelesen haben: Ich meine ursprüngliche Antwort Ich sage, "dass ich Ihnen meins leihen könnte" falls Sie meinen Vorschlag mögen. –

Antwort

1

Von OWASP Empfehlungen auf Preventing Unvalidated Redirects and Forwards:

Es wird empfohlen, dass eine solche Zieleingabe auf einen Wert abgebildet werden, eher als die tatsächliche URL oder einen Teil der URL und den Server-Side-Code übersetzen diese Wert für die Ziel-URL.

So ein sicherer Ansatz würde einige Schlüssel zu tatsächlichen URLs werden Abbildung:

// https://example.com/login#destination 

var keyToUrl = { 
    destination: 'https://example.com/destination', 
    defaults: 'https://example.com/default' 
}; 

function onSuccessfulLogin() { 
    var hash = location.hash.substring(1); 
    var url = keyToUrl[hash] || keyToUrl.defaults; 

    location.replace(url); 
} 

Sie auch nur Pfad Teil der URL Bereitstellung könnte in Erwägung ziehen und es mit einem Hostnamen im Code angehängt:

// https://example.com/login#destination 

function onSuccessfulLogin() { 
    var path = location.hash.substring(1); 
    var url = 'https://example.com/' + path; 

    location.replace(url); 
} 

Ich würde aber bei der Zuordnung bleiben.

+0

Ah, ja vorläufig 'location.origin + '/'' ('https: // example.com') sieht wie eine gute Lösung aus. Entschuldigung, aber in diesem speziellen Projekt werden wir keine Mappings verwenden, trotz des zusätzlichen Wertes, den sie bieten würden. –

0

Das ist ein sehr guter Punkt über die XSS-Schwachstelle.

Ich glaube, alle Protokolle nur Zeichen des englischen Alphabets verwenden, so ein regulärer Ausdruck wie /^[a-z]+:/i würde für diejenigen überprüfen. Alternativ, wenn wir mehr inklusive Gefühl sind, können /^[^:\/?]+:/ alles andere als ein von einem : gefolgt / oder ?. Dann können wir das mit /^\/\/ kombinieren für ein Protokoll freien URL zu testen, die uns gibt:

// Either 
var rexIsProtocol = /(?:^[a-z]+:)|(?:^\/\/)/i; 
// Or 
var rexIsProtocol = /(?:^[^:\/?]+:)|(?:^\/\/)/i; 

Dann wird der Test ist wie folgt:

var url = location.hash.substring(1).trim(); // trim to deal with whitespace 
if (rexIsProtocol.test(url)) { 
    // It starts with a protocol 
} else { 
    // It doesn't 
} 

Das heißt, der einzige, den ich glaube, Sie muss besonders gestört werden, ist das javascript: Pseudo-Protcol, also könnten Sie nur dafür testen.