Martin Suchan – BloQ Random #WPdev stuff

19Oct/152

Hacking UWP WebView Part 1. Displaying HTTPS page with invalid certificate in UWP WebView

This is a first part of my small series of blogposts about unlocking hidden features of Windows 10 UWP WebView.

If you want to display web page content inside your Windows 10 UWP app, you need to use the WebView class. In standard scenarios you just set the Source property or use the Navigate(Uri) method to the target page and if your Internet connection works, the page shows up just like in Microsoft Edge.

But there is a caveat when using the method. If the target page is available only on HTTPS protocol and the Domain certificate for the target web is not valid (expired, self-signed, invalid domain name...) then the page won't load, you only get the OnNavigationFailed event with WebErrorStatus.CertificateIsInvalid or similar indicator.

As you probably know, in standard browsers like IE, Chrome, Firefox or Edge there is always a semi-hidden option to override this certificate error and continue navigation to that page anyway, usually with a big warning that the connection won't be secure and possible attacker could be eavesdropping your connection or even modifying the transmitted data. Yes, that's the risk here, even though in 99.99% of cases no-one is actually eavesdropping you, only the server is just not properly configured.

Capture

If the target site uses self-signed HTTPS certificate and this self-signed certificate is otherwise valid for the target domain, there is a solution how to make the WebView work in this case - you just need to add the specific certificate inside Package.appxmanifest -> Declarations -> Certificates whitelist. Here you select the .cer file for your site with "TrustedPeople" as the Store name and all should just work. Another solution is to whitelist the Root certificate for this custom domain certificate and trust this self-signed Root. Unfortunately this solution only works for specific sites that you whitelist, not for any site with self-signed certificate.

Capture

In some valid scenarios you might need to display web content of HTTPS page with invalid certificate inside your Windows Store app, but how to do it? There is no property or method in WebView to override this behavior and enable navigation to a page with invalid certificate, but luckily I found a solution!

WebView in Windows Store apps has a method called NavigateToLocalStreamUri(Uri source, IUriToStreamResolver streamResolver) which is designed for loading local HTTP page with external resources, like HTML pages with extern CSS styles or images, that cannot be loaded just by using NavigateToString(Uri). How to use that method for loading local pages is shown in this short article.

In short you create special object implementing the IUriToStreamResolver interface, that has method IAsyncOperation<IInputStream> UriToStreamAsync(Uri uri). In this method you can handle all HTTP requests from the WebView and load your page resources from any source you want!

The solution

Even though the method is called NavigateToLocalStreamUri, it works just fine even when I manually download the requested resources from the Internet in the IUriToStreamResolver object using the HttpClient class. And with the fact, that HttpClient class allows us to ignore specific certificate errors when connecting to HTTPS web sites, we have a solution for our problem!

Here's a quick and ugly proof of concept for the problem:

public sealed partial class MainPage
{
    public MainPage()
    {
        InitializeComponent();
    }
 
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        Uri uri = new Uri("https://expired.identrustssl.com/");
 
        Uri localStreamUri = Web.BuildLocalStreamUri("MyTag", "/");
        BadHttpsStreamResolver resolver = new BadHttpsStreamResolver(uri, localStreamUri);
        Web.NavigateToLocalStreamUri(localStreamUri, resolver);
    }
}
 
public sealed class BadHttpsStreamResolver : IUriToStreamResolver
{
    private readonly string baseUri;
    private readonly string localStreamUri;
    private readonly HttpClient hc;
 
    public BadHttpsStreamResolver(Uri baseUri, Uri localStreamUri)
    {
        this.baseUri = baseUri.ToString();
        this.localStreamUri = localStreamUri.ToString();
        HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
        // specify here which certificate errors should we ignore
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
        hc = new HttpClient(filter);
    }
 
    public IAsyncOperation UriToStreamAsync(Uri uri)
    {
        // TODO better uri validation and conversion
        Uri targetUri = new Uri(uri.ToString().Replace(localStreamUri, baseUri));
        return GetInputStream(targetUri).AsAsyncOperation();
    }
 
    public async Task GetInputStream(Uri targetUri)
    {
        try
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, targetUri);
            HttpResponseMessage response = await hc.SendRequestAsync(request);
            IInputStream stream = await response.Content.ReadAsInputStreamAsync();
            return stream;
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Exception {0}", ex);
            return null;
        }
    }
}

How this works? We have a WebView named "Web" in the MainPage XAML. We have a sample page https://expired.identrustssl.com/ with expired domain certificate. First we create local stream Uri using the Web.BuildLocalStreamUri("MyTag", "/") method. Then we create the instance of our online IUriToStreamResolver. In our stream resolver we just transform every local Uri to the proper online Uri and use the HttpClient class instance with HttpBaseProtocolFilter ignoring ChainValidationResult.Expired errors for downloading all resources that the page needs.

Here you can see, how the sample page is displayed just fine in my UWP Store app. Note this page uses external CSS file and three external images, all these resources were loaded using my BadHttpsStreamResolver class.

Capture

Possible problems with this solution

Sadly this solution is not almighty. It works fine for reasonably simple web sites, but not for highly dynamic sites using AJAX XMLHttpRequest, WebSockets or other advanced stuff. This method also won't work for POST and other non-GET request on that page.

There is a project called Web Application Template that tries to solve some of these advanced scenarios, I've not tried it but it looks quite promising especially for solving the XMLHttpRequest problem by using injected proxy class that redirects all XMLHttpRequest calls into the C# code.

Conclusion

I have shown in this article that it's possible to display simple HTTPS pages with invalid certificate inside WebView in UWP Windows Store apps. For sites with valid self-signed certificate it's possible to use whitelisted certificate or certificate root in app manifest, for pages with other certificate validation errors it's possible to handle all HTTP request with custom IUriToStreamResolver class.

In my opinion the fact, that WebView does not support opt-in for displaying HTTPS pages with invalid certificates is a problem that should be fixed. If you agree with me, please vote for these two UserVoice issues, thanks!

Did you like this article, have you found it helpful, or do you know other methods for displaying HTTPS page with invalid certificate in UWP WebView? Please let me know either here in the discussion or on my Twitter, thanks!

17Oct/1415

How to deploy your own NuGet server on Azure Website in 15 minutes

Let's imagine this typical scenario: You are an indie developer or a company developing apps in Visual Studio. You have already developed and use several own useful libraries across various projects. Right now you are maintaining each of these libraries in separate Git/TFS repository and adding these libraries as submodules to your projects. Because these libraries are hierarchically dependent one on another, it's quite hard to maintain the dependencies and changes properly. You've thought about packaging these libraries as separate NuGet packages, but adding them to public nuget.org gallery is not an option since these libraries contain private knowhow.

In this article I'll demonstrate, how to deploy your own NuGet Server on free instance of Azure Website, secure it with Basic HTTP Authentication, setup this new server so it can be used from Visual Studio, easily create automatic PowerShell scripts for deploying these libraries as NuGet packages to your server, use these NuGet packages in your projects and also how to achieve all this in just couple of minutes!

14May/110

Creating ‘select multiple’ element in IE6 using jQuery

I was facing recently strange problem with creating <select> tag with 'multiple' attribute in IE6. Normally it's done using $("<select>").attr("multiple", true), but this does not work in IE6 - the crated select element was simple every time, without multiple choices. Setting 'multiple' attribute in IE6 programatically just doesn't work. I spent lot of time finding some workaround, but the solution I discovered is pretty simple, just use this object constructor:

$("<select multiple='multiple'>")

It's not 100% clean solution, but it works in IE6 and that's important.

If you know better solution, you might update the jQuery I created for this issue: http://bugs.jquery.com/ticket/9231

Tagged as: , No Comments
31Mar/110

New line characters in XML

Just a small hint - have you ever been wondering, how to put newline characters into XML document? typical string with escape sequence like '\n' can't be used, because this string has no special meaning in XML. Instead of you need to use hexadecimal escaped character: &#10; for newline or &#13; for carriage return. Simple, isn't it?

Tagged as: No Comments
18Feb/116

How to make text unselectable on HTML page

How to make text on a web page unselectable? There are several possible approaches - using overlay transparent image in front of the text, using image with text instead of text, or using the following best practice:

There are currently two independent ways for preventing text selection: using CSS style user-select: none; and using attribute on target element unselectable="on". Unfortunately only subset of browsers supports the first one and another subset the second one. To be more precise the CSS style user-select: none; is currently not supported anywhere, but you can use these browser specific styles:
-webkit-user-select: none; - working in Chrome and Safari
-moz-user-select: none; - working in FireFox

On the other hand unselectable="on" is working in Internet Explorer 6+ and in Opera. There is actually one simple hiccup with this property - you need to use it on each sub element in you text to prevent the selection across elements, but I'm sure you'll figure this out 🙂

Summing that up: using the style and the attribute at the same time on your text you can easily prevent selecting anything.

Example: you can't select this sentence 😛

Tagged as: , 6 Comments
15Feb/111

Disabling key down event propagation in JavaScript

Imagine this non-trivial problem: you have div element with overflow: auto; and long text inside. The scrollbar appears automatically. Normally when the div is focused pressing keys Up or Down causes moving the content up or down. But what if you don't want to scroll the content on keydown event?