Uncontrolled external site redirect
Need
Controlled and secure external site redirects
Context
- Usage of Dart for building cross-platform mobile, web, and desktop applications
- Usage of Shelf for managing data storage and retrieval
Description
Non compliant code
import 'package:shelf/shelf.dart' as shelf;
shelf.Response handleRequest(shelf.Request request) {
var redirectUrl = request.url.queryParameters['redirectUrl'];
return shelf.Response.found(redirectUrl);
}
In the above code, the handleRequest
function handles incoming requests and retrieves a redirectUrl
from the query parameters of the request. Then, it redirects the user to the provided redirectUrl
without any validation or control.
This is a security vulnerability known as "Uncontrolled External Site Redirect" or "Open Redirect". An attacker could manipulate the redirectUrl
to redirect users to malicious websites. For example, the attacker could send a link to a user that points to your application but includes a redirectUrl
to a phishing site. If the user clicks on the link, they would be redirected to the phishing site while believing they are still interacting with your application. This could lead to various types of attacks like phishing, stealing user's credentials, or delivering malware.
Steps
- Validate the redirect URL to ensure it's a trusted and expected URL.
- Do not rely solely on user-provided data for the redirect URL, instead use a mapping of allowed URLs.
- Implement a whitelist of trusted URLs to which the application can redirect.
- Avoid direct use of user input in the 'Response.found' method.
- If possible, avoid redirection based on user input entirely.
Compliant code
import 'package:shelf/shelf.dart' as shelf;
const List<String> trustedUrls = ['https://trustedurl1.com', 'https://trustedurl2.com'];
shelf.Response handleRequest(shelf.Request request) {
var redirectUrl = request.url.queryParameters['redirectUrl'];
if (!trustedUrls.contains(redirectUrl)) {
return shelf.Response.forbidden('Invalid redirect URL');
}
return shelf.Response.found(redirectUrl);
}
The updated code includes a list of trustedUrls
which are the only URLs to which the application is allowed to redirect. When a request is received, the redirectUrl
is extracted from the query parameters as before. However, before the redirection is made, the redirectUrl
is checked against the trustedUrls
list. If the redirectUrl
is not in the list, a 403 Forbidden response is returned, indicating that the requested redirect URL is not allowed. If the redirectUrl
is in the list, the redirection is made as before.
This approach ensures that only trusted URLs are used for redirection, preventing an attacker from manipulating the redirect URL to an untrusted site. It also avoids the direct use of user input in the Response.found
method, as the input is validated before it is used.