Back to Devexpress

Suppress Control Requests to Download Data from External URLs

generalinformation-404440-security-suppress-control-requests-to-download-data-from-external-ur-ls.md

latest11.6 KB
Original Source

Suppress Control Requests to Download Data from External URLs

  • Oct 21, 2024
  • 6 minutes to read

Certain DevExpress UI controls can download data over the internet. For example, the Map Control can download terrain data and the WinForms PictureEdit can download images passed as URLs to the PictureEdit.LoadAsync(String) method. These requests can be initiated in your code or via the internal control engine.

This topic explains how to spot, analyze, and prohibit unwanted download requests.

Apply Global Download Restrictions

The default security policy does not limit web connections. Call one of the following DevExpress.Data.AsyncDownloadPolicy methods at application startup to apply a restrictive policy:

csharp
static void Main() {
    DevExpress.Data.AsyncDownloadPolicy.SuppressAll();  
    Application.Run(new Form1());  
}
vb
Shared Sub Main()
    DevExpress.Data.AsyncDownloadPolicy.SuppressAll()
    Application.Run(New Form1())
End Sub

Trusted Resources

If a restrictive download policy is active, you may want to create a “safe” resource whitelist. Downloads from whitelist resources bypass policy restrictions. To “trust’ a specific resource, call the static RegisterTrustedUri method:

csharp
static void Main() {  
    DevExpress.Data.AsyncDownloadPolicy.SuppressAll();
    DevExpress.Data.AsyncDownloadPolicy.RegisterTrustedUri(new Uri("https://www.devexpress.com"));
    Application.Run(new Form1());  
}
vb
Shared Sub Main()
    DevExpress.Data.AsyncDownloadPolicy.SuppressAll()
    DevExpress.Data.AsyncDownloadPolicy.RegisterTrustedUri(New Uri("https://www.devexpress.com")) 
    Application.Run(New Form1())
End Sub

Note

Masked resource registration is not available. If you require to validate various requests made to the same host, apply the SuppressAll policy and handle the Downloading event to manually inspect each connection.

Track Control Actions

To track user/app initiated downloads and execute custom actions in response, handle the following DevExpress.Data.AsyncDownloadPolicy events. These events can be raised in a separate thread.

The “Probing” Event

The Probing event allows you to spot the probing of external resources before an actual attempt to download data.

csharp
void OnProbing(object sender, ProbingEventArgs e) {
    var shouldClose = XtraMessageBox.Show("Notification",
        "Probing the " + e.Uri.AbsoluteUri + " URL was detected. Close the connection?",
        MessageBoxButtons.YesNo);
    e.Cancel = (shouldClose == DialogResult.Yes) ? true : false;
}
vb
Private Sub OnProbing(ByVal sender As Object, ByVal e As ProbingEventArgs)
    Dim shouldClose = XtraMessageBox.Show("Notification", "Probing the " & e.Uri.AbsoluteUri & " URL was detected. Close the connection?", MessageBoxButtons.YesNo)
    e.Cancel = If((shouldClose = DialogResult.Yes), True, False)
End Sub

The “Downloading” Event

Downloading is a cancelable event that allows you to spot an initiated download, check connection parameters, and cancel (or allow, if the SupressAll policy is active) the operation.

csharp
void OnDownloading(object sender, DownloadingEventArgs e) {
    e.Cancel = !e.Uri.AbsoluteUri.StartsWith(@"https://www.devexpress.com");
}
vb
Private Sub OnDownloading(ByVal sender As Object, ByVal e As DownloadingEventArgs)
    e.Cancel = Not e.Uri.AbsoluteUri.StartsWith("https://www.devexpress.com")
End Sub

Tip

Different DevExpress UI components with the same functionality (for example, separate PictureEdit controls that load images from URI paths) utilize the same HttpClient. As a result, the event’s e.ValueType parameter is the same for all individual controls (for aforementioned PictureEdit controls, ValueType returns ImageOrSvgImageResult). This technique allows you to identify the group of controls to which an individual control (that initiated the download) belongs.

csharp
public Form1() {
    InitializeComponent();
    AsyncDownloadPolicy.Downloading += AsyncDownloadPolicy_Downloading;
}
Dictionary<int, string> whitelist = new Dictionary<int, string>() {
    { 0, "www.devexpress.com" },
    { 1, "community.devexpress.com" },
    { 2, "docs.devexpress.com" },
    { 3, "supportcenter.devexpress.com" }
};
private void AsyncDownloadPolicy_Downloading(object sender, AsyncDownloadPolicy.DownloadingEventArgs e) {
    string result = e.ValueType.Name;
    // Checks whether a picture editor initiated the download.
    if(result == "ImageOrSvgImageResult")
        // Cancels downloading from domains that are not in the white list.
        e.Cancel = !whitelist.Values.Contains(e.Uri.Authority);
}
private void loadImageButton_Click(object sender, EventArgs e) {
    pictureEdit1.LoadAsync(/* YOUR_URL */);
}
vb
Public Sub New()
    InitializeComponent()
    AddHandler AsyncDownloadPolicy.Downloading, AddressOf AsyncDownloadPolicy_Downloading
End Sub
Private whitelist As New Dictionary(Of Integer, String)() From {
    { 0, "www.devexpress.com" },
    { 1, "community.devexpress.com" },
    { 2, "docs.devexpress.com" },
    { 3, "supportcenter.devexpress.com" }
}
Private Sub AsyncDownloadPolicy_Downloading(ByVal sender As Object, ByVal e As AsyncDownloadPolicy.DownloadingEventArgs)
    Dim result As String = e.ValueType.Name
    ' Checks whether a picture editor initiated the download.
    If result = "ImageOrSvgImageResult" Then
        ' Cancels downloading from domains that are not in the white list.
        e.Cancel = Not whitelist.Values.Contains(e.Uri.Authority)
    End If
End Sub
Private Sub loadImageButton_Click(ByVal sender As Object, ByVal e As EventArgs)
    pictureEdit1.LoadAsync("YOUR_URL")
End Sub

The “Downloaded” Event

If you did not cancel a download on the Downloading event, the notification Downloaded event fires once the download has completed.

csharp
void OnDownloaded(object sender, DownloadedEventArgs e) {
    // Log.WriteMessage("Data from " + e.Uri.AbsoluteUri + " was downloaded");
}
vb
Private Sub OnDownloaded(ByVal sender As Object, ByVal e As DownloadedEventArgs)
    ' Log.WriteMessage("Data from " & e.Uri.AbsoluteUri & " was downloaded")
End Sub

The “Failed” Event

The AsyncDownloadPolicy.Failed event occurs if an external resource fails to load. Handle the Failed event to supply the content instead of the resource that could not be loaded or throw an exception.

Use the e.Content event parameter to specify the content instead of an external resource that fails to load. Call the e.Throw() method to throw an exception.

The following example handles the Failed event to display a placeholder image in a WinForms PictureEdit if an external image fails to load:

csharp
public Form1() {
    InitializeComponent();
    DevExpress.Data.AsyncDownloadPolicy.Failed += AsyncDownloadPolicy_Failed;
}

void AsyncDownloadPolicy_Failed(object sender, DevExpress.Data.AsyncDownloadPolicy.FailedEventArgs e) {
    if (e.ValueType.Name == "ImageOrSvgImageResult") {
        MemoryStream stream = new MemoryStream();
        /* A placeholder image is obtained from the DevExpress SvgImageCollection.
         * The placeholder image was added to the SvgImageCollection at design time.
         */
        var errorImage = svgImageCollection1[0];
        errorImage.Save(stream);
        e.Content = stream;
    }
}

async void btnLoadImage_Click(object sender, EventArgs e) {
    await pictureEdit1.LoadAsync("EXTERNAL_IMAGE_URL");
}
vb
Public Sub New()
    InitializeComponent()
    DevExpress.Data.AsyncDownloadPolicy.Failed += AsyncDownloadPolicy_Failed
End Sub

Private Sub AsyncDownloadPolicy_Failed(ByVal sender As Object, ByVal e As DevExpress.Data.AsyncDownloadPolicy.FailedEventArgs)
    If e.ValueType.Name = "ImageOrSvgImageResult" Then
        Dim stream As New MemoryStream()
        Dim errorImage = svgImageCollection1(0)
        errorImage.Save(stream)
        e.Content = stream
    End If
End Sub

Async Sub btnLoadImage_Click(ByVal sender As Object, ByVal e As EventArgs)
    Await pictureEdit1.LoadAsync("EXTERNAL_IMAGE_URL")
End Sub

Custom HTTP Client Parameters

You can handle the ConfigureHttpClient client to customize settings of a standard System.Net.Http.HttpClient component that DevExpress components use to download data: the default proxy, base address, cache size, and more.

For example, the default buffer size of an HttpClient is 2 gigabytes. PictureEdit controls reduce this size to 4096 bytes. If you attempt to download a larger image, the following code…

csharp
async void OnFormLoad(object sender, EventArgs e) {
    await pictureEdit1.LoadAsync("...");
}
vb
Private Async Sub OnFormLoad(ByVal sender As Object, ByVal e As EventArgs)
    Await pictureEdit1.LoadAsync("...")
End Sub

…fires the “System.Net.Http.HttpRequestException: Cannot write more bytes to the buffer than the configured maximum buffer size: 4194304” exception. The following sample illustrates how to raise this limit to 16MB.

csharp
void OnConfigureHttpClient(object sender, ConfigureHttpClientEventArgs e) {
    e.Client.MaxResponseContentBufferSize = 1024*1024*16;
}
vb
Private Sub OnConfigureHttpClient(ByVal sender As Object, ByVal e As ConfigureHttpClientEventArgs)
    e.Client.MaxResponseContentBufferSize = 1024*1024*16
End Sub

You can also modify values for the static AsyncDownloadPolicy class constants. Do so if you wish to set a global limit that can be changed within the ConfigureHttpClient event for individual controls.

csharp
DevExpress.Data.AsyncDownloadPolicy.DefaultResponseContentBufferSizeForHttpClient = 1024 * 1024 * 4; // 4MB
DevExpress.Data.AsyncDownloadPolicy.DefaultBufferSizeForContentCopy = 1024 * 16; // 16KB
vb
' 4MB
DevExpress.Data.AsyncDownloadPolicy.DefaultResponseContentBufferSizeForHttpClient = 1024 * 1024 * 4
' 16KB
DevExpress.Data.AsyncDownloadPolicy.DefaultBufferSizeForContentCopy = 1024 * 16