logo

Uncontrolled external site redirect - Dart


Need

Controlled and secure external site redirects


Context

  1. Usage of Dart for building cross-platform mobile, web, and desktop applications
  2. Usage of Shelf for managing data storage and retrieval

Description

Insecure Code Example

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

  1. Validate the redirect URL to ensure it's a trusted and expected URL.
  2. Do not rely solely on user-provided data for the redirect URL, instead use a mapping of allowed URLs.
  3. Implement a whitelist of trusted URLs to which the application can redirect.
  4. Avoid direct use of user input in the 'Response.found' method.
  5. If possible, avoid redirection based on user input entirely.

Secure Code Example

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.


References

  • 156 - Uncontrolled external site redirect

  • Last updated

    2023/09/18