Uncontrolled external site redirect - Dart

Uncontrolled external site redirect - Dart

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 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.

References