Bug 814141. Cross-site redirects of a CORS request should null out the request origin. r=sicking

This commit is contained in:
Boris Zbarsky 2012-11-29 18:23:55 -05:00
Родитель eb28b72392
Коммит 8915de2bfc
3 изменённых файлов: 91 добавлений и 5 удалений

Просмотреть файл

@ -350,6 +350,7 @@ nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
bool aWithCredentials) bool aWithCredentials)
: mOuterListener(aOuter), : mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal), mRequestingPrincipal(aRequestingPrincipal),
mOriginHeaderPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials && !gDisableCORSPrivateData), mWithCredentials(aWithCredentials && !gDisableCORSPrivateData),
mRequestApproved(false), mRequestApproved(false),
mHasBeenCrossSite(false), mHasBeenCrossSite(false),
@ -364,6 +365,7 @@ nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
const nsTArray<nsCString>& aPreflightHeaders) const nsTArray<nsCString>& aPreflightHeaders)
: mOuterListener(aOuter), : mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal), mRequestingPrincipal(aRequestingPrincipal),
mOriginHeaderPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials && !gDisableCORSPrivateData), mWithCredentials(aWithCredentials && !gDisableCORSPrivateData),
mRequestApproved(false), mRequestApproved(false),
mHasBeenCrossSite(false), mHasBeenCrossSite(false),
@ -387,6 +389,7 @@ nsCORSListenerProxy::Init(nsIChannel* aChannel, bool aAllowDataURI)
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mOuterListener = nullptr; mOuterListener = nullptr;
mRequestingPrincipal = nullptr; mRequestingPrincipal = nullptr;
mOriginHeaderPrincipal = nullptr;
mOuterNotificationCallbacks = nullptr; mOuterNotificationCallbacks = nullptr;
} }
return rv; return rv;
@ -404,6 +407,8 @@ nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(channel, getter_AddRefs(uri)); NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
if (uri) { if (uri) {
// OK to use mRequestingPrincipal since preflights never get
// redirected.
sPreflightCache->RemoveEntries(uri, mRequestingPrincipal); sPreflightCache->RemoveEntries(uri, mRequestingPrincipal);
} }
} }
@ -488,7 +493,7 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) { if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) {
nsAutoCString origin; nsAutoCString origin;
rv = nsContentUtils::GetASCIIOrigin(mRequestingPrincipal, origin); rv = nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!allowedOriginHeader.Equals(origin)) { if (!allowedOriginHeader.Equals(origin)) {
@ -623,12 +628,47 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsCOMPtr<nsIURI> oldURI; nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI)); NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
if (oldURI) { if (oldURI) {
// OK to use mRequestingPrincipal since preflights never get
// redirected.
sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal); sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal);
} }
} }
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI); aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
return NS_ERROR_DOM_BAD_URI; return NS_ERROR_DOM_BAD_URI;
} }
if (mHasBeenCrossSite) {
// Once we've been cross-site, cross-origin redirects reset our source
// origin.
nsCOMPtr<nsIPrincipal> oldChannelPrincipal;
nsContentUtils::GetSecurityManager()->
GetChannelPrincipal(aOldChannel, getter_AddRefs(oldChannelPrincipal));
nsCOMPtr<nsIPrincipal> newChannelPrincipal;
nsContentUtils::GetSecurityManager()->
GetChannelPrincipal(aNewChannel, getter_AddRefs(newChannelPrincipal));
if (!oldChannelPrincipal || !newChannelPrincipal) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
if (NS_SUCCEEDED(rv)) {
bool equal;
rv = oldChannelPrincipal->Equals(newChannelPrincipal, &equal);
if (NS_SUCCEEDED(rv)) {
if (!equal) {
// Spec says to set our source origin to a unique origin.
mOriginHeaderPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
if (!mOriginHeaderPrincipal) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
return rv;
}
}
} }
// Prepare to receive callback // Prepare to receive callback
@ -729,7 +769,7 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, bool aAllowDataURI)
// Add the Origin header // Add the Origin header
nsAutoCString origin; nsAutoCString origin;
rv = nsContentUtils::GetASCIIOrigin(mRequestingPrincipal, origin); rv = nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel); nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);

Просмотреть файл

@ -66,7 +66,11 @@ private:
nsresult CheckRequestApproved(nsIRequest* aRequest); nsresult CheckRequestApproved(nsIRequest* aRequest);
nsCOMPtr<nsIStreamListener> mOuterListener; nsCOMPtr<nsIStreamListener> mOuterListener;
// The principal that originally kicked off the request
nsCOMPtr<nsIPrincipal> mRequestingPrincipal; nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
// The principal to use for our Origin header ("source origin" in spec terms).
// This can get changed during redirects, unlike mRequestingPrincipal.
nsCOMPtr<nsIPrincipal> mOriginHeaderPrincipal;
nsCOMPtr<nsIInterfaceRequestor> mOuterNotificationCallbacks; nsCOMPtr<nsIInterfaceRequestor> mOuterNotificationCallbacks;
bool mWithCredentials; bool mWithCredentials;
bool mRequestApproved; bool mRequestApproved;

Просмотреть файл

@ -859,7 +859,7 @@ function runTest() {
}, },
], ],
}, },
{ pass: 1, { pass: 0,
method: "GET", method: "GET",
hops: [{ server: "http://example.com", hops: [{ server: "http://example.com",
allowOrigin: origin allowOrigin: origin
@ -869,6 +869,16 @@ function runTest() {
}, },
], ],
}, },
{ pass: 1,
method: "GET",
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://example.org",
allowOrigin: "*"
},
],
},
{ pass: 0, { pass: 0,
method: "GET", method: "GET",
hops: [{ server: "http://example.com", hops: [{ server: "http://example.com",
@ -902,7 +912,7 @@ function runTest() {
}, },
], ],
}, },
{ pass: 1, { pass: 0,
method: "GET", method: "GET",
hops: [{ server: "http://example.com", hops: [{ server: "http://example.com",
allowOrigin: origin allowOrigin: origin
@ -918,6 +928,38 @@ function runTest() {
}, },
], ],
}, },
{ pass: 0,
method: "GET",
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.example.org:8000",
allowOrigin: origin
},
{ server: "http://sub2.xn--lt-uia.example.org",
allowOrigin: "*"
},
{ server: "http://sub1.test1.example.org",
allowOrigin: "*"
},
],
},
{ pass: 1,
method: "GET",
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.example.org:8000",
allowOrigin: "*"
},
{ server: "http://sub2.xn--lt-uia.example.org",
allowOrigin: "*"
},
{ server: "http://sub1.test1.example.org",
allowOrigin: "*"
},
],
},
{ pass: 0, { pass: 0,
method: "GET", method: "GET",
hops: [{ server: "http://example.com", hops: [{ server: "http://example.com",
@ -934,7 +976,7 @@ function runTest() {
}, },
], ],
}, },
{ pass: 1, { pass: 0,
method: "GET", method: "GET",
hops: [{ server: "http://example.com", hops: [{ server: "http://example.com",
allowOrigin: origin allowOrigin: origin