Workstation Woes[2]

by Administrator 22. March 2008 23:21

I am now one NewEgg hat and $50 better off than I was the other day, but my replacement part still has not shipped.  So much for having it overnighted to me.  In addition to the claimed system glitches that kept this from shipping when it was supposed to, their systems showed on Friday that the part was boxed but no tracking number had made it out yet.  This morning, I find an email notification that my $$ has been refunded for the part.  I'm not sure if this is additional goodwill or another mistake, but I'll have to wait until Monday to find out.


Yaron Brook on Free Speech

by Administrator 21. March 2008 16:16

I encourage you to leave comments on Forbes as well.


Workstation Woes[1]

by Administrator 20. March 2008 17:02

So, I set about to RMA my motherboard on Wedesday.  To make a long story short, they gave me a UPS shipping lable and the transit times plus their RMA processing time put the round trip at something like 3 weeks for me.  This is complete BS since by then my window to return/exchange the other parts will be gone.  I shouldn't have to wait a month for something I bought to be made right.  I called NewEgg's customer support to explain this to them, and lo and behold without the slightest bit of resistance they agree to overnight me a new one without making me wait on the whole RMA Process.  I left them a strongly positive note at Reseller ratings and I should be in Quad Core Heaven Friday night or Saturday.

There's an important item to not here.  A DOA Asus motherboard is not the fault of NewEgg, but I am more directly their customer than a customer of Asus.  A company cannot directly pin their customer's satisfaction on the performance of their own vendors.  A layer of indirection is needed.


Script Debugging in IE8

by Administrator 19. March 2008 03:19

It would appear, at least on my machine, that I can add "No script debugging" to my list of IE8 complaints.  Despite making the necessary Internet Options changes I can't hit breakpoints in javascript in VS2008 any longer.  It's a beta browser and I don't really need this feature, but be warned.


Securing ClickOnce Deployments

by Administrator 18. March 2008 16:05

Securing ClickOnce Deployments


I have written in the past (,guid,da078e56-eb5b-4616-8605-13c38d54efc3.aspx) about some of the plumbing involved in ClickOnce and Client Application Services geared towards preventing unauthorized operation of a client application.  At the time I noted that there is at least one issue with this level of “security”.  While it does keep unauthorized users from running your application, it doesn’t protect your code.  As has been lamented elsewhere, a ClickOnce application deployed on the Internet does not have any supported means of keeping people from getting your code.  Even with obfuscation this may be undesirable: we don’t want people getting a hold of the application manifest file and subsequently the assemblies.

A while back I started down a few paths to secure the code and the Application Deployment Manifest.  I have a pretty decent partial solution for protecting your code.  Read on.

Step 1: Security by Obscurity?

Your ClickOnce deployment consists of a deployment manifest, the executable, and all of the referenced assemblies and content files required to run your Windows Forms or WPF application.  By turning off directory browsing and not having any publicly available links to your .application file you can discourage casual spelunking.   I’m not very satisfied with this as the only aspect of a code protection solution. 

It’s fairly unlikely than an uneducated attacker (outside job) could guess the names of the assemblies that make up your application.  If only you could lock down the .application file…

Eliminating the Obvious Suspects

To get the obvious thoughts out of the way:

1)      You cannot protect a ClickOnce application deployment manifest using Forms authentication.  The client side aspects of ClickOnce that get installed with .NET 2.0 can’t handle Forms authentication.

2)      Windows Authentication is at best a poor option here, and not a real option for most people.  The performance of “Remember me” in an NTLM challenge form is flaky and is not supported in the Internet zone.

3)      ClickOnce does not support HTTP Basic authentication schemes.

An Idea

One nice thing about ClickOnce is that, like Silverlight, it’s really a Client Side technology.  You don’t NEED to be running Windows Server and IIS in order to benefit from these technologies.  However since I do know some Microsoft server side technologies I had an idea.

I wanted to associate a Product Key of some kind with a ClickOnce deployment.  Product Keys are not the final word on application licensing but it is a means of accountability.  Look at Windows Genuine Advantage: you can’t keep people from sharing CD keys but if you see the same CD key being used 1,000 times from different hosts all over the nation, you can shut it down.  Given a test deploy URL:


It would be nice to be able to do something like this:


… and have it be meaningful.

HttpHandler Attempt 1

To keep people from getting at my .application file, I thought a simple IHttpHandler implementation configured to intercept requests for the .application extension could be the answer. 

Web.config and sample code:

<add verb="GET,HEAD" path="*.application" type="ClickOnceHandler"/>

    public void ProcessRequest(HttpContext context)


        string key = context.Request.QueryString["key"];

        if (ValidateKey(key))


            //Go ahead and give up the .application file




            throw new ApplicationException("Invalid or missing product Key");



I had a notion of allowing users to sign up for the application online by entering a privately exchanged product key in a web page:

The code behind for the install button is simple:

Response.Redirect("Publish/MyApp.application?key=" + _prodKeyTxt.Text);

Sadly, the solution is not this simple.  The Client side ClickOnce libraries exhibit some bizarre behavior.  Using Fiddler and the debugger, this is what I see:

1)      The .application file is requested and the HttpHandler validates the product key.

2)      Mysteriously, ClickOnce requests the entire URL of the .application file again: http://localhost:5785/CarSpot/Publish/MyApp.application?key=123; The HttpHandler validates the key and writes the contents of the .application file to the Response.

3)      Mysteriously (and infuriatingly) ClickOnce requests the .application file again: http://localhost:5785/CarSpot/Publish/MyApp.application ; note the missing piece of the query string.

I was unable to dig up any reason for what ClickOnce is doing here, but I do know that without getting that product key my scheme is ruined.  Looking at the .application file there’s a likely explanation:

<deploymentProvider codebase=" /Publish/MyApp.application" />

This is where I left it for a long time, while dealing with some other things at work.

HttpHandler Attempt 2

The next, step, I felt, was to dynamically alter the application deployment file so that the provider codebase as recorded by the client included the product key on the URL.  I added some code to do this:

                XmlDocument doc = new XmlDocument();


                //Get around the issue of the query strong not being

                doc.DocumentElement["deployment"]["deploymentProvider"].Attributes["codebase"].Value += "?key=123";

However, this introduces another issue.  When you choose to give your ClickOnce application Full Permissions (Otherwise why not go the XBAP route?) you will find that you are signing it.   Look what Visual Studio did for me:

<publisherIdentity name="CN=CORNZOR\Damon" issuerKeyHash="" /><Signature Id="StrongNameSignature" {nothing to see here}</Signature></asmv1:assembly>

Yes, my laptop is named cornzor.  At any rate, this signature is there for your clients’ protection: if a man in the middle alters the XML payload of the .application file it will not verify and ClickOnce will refuse to do anything further.  Since I’m not a man in the middle I assumed there must be a way to dynamically do what I want.

I started out with the two links above, researching how the manifests are generated, and initially experimenting with manually generating un-signed deployment manifests from the command line.  After an infuriating XML character encoding setback, these articles did lead me to the answer.  Now I can protect my .application file in an appropriate fashion.

HttpHandler Complete

The articles above give us the tools we need to put the product key in the application manifest for each client and re-sign on the fly.

    /// <summary>

    /// Execute whatever business logic will make this a valid program key

    /// </summary>

    /// <param name="key"></param>

    /// <returns></returns>

    protected bool ValidateKey(string key)


        return key.Equals("123");


    /// <summary>

    /// Create a new signature in the deployment manifest

    /// </summary>

    /// <param name="path"></param>

    /// <param name="pfxPath"></param>

    protected void ReSign(string path, string pfxPath)


        string mageArgFormat = "-Sign {0} -CertFile {1} -ToFile {2}";

        string mageExe = @"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\mage.exe";

        string mageArgs = string.Format(mageArgFormat, path, pfxPath, path);

        ProcessStartInfo info = new ProcessStartInfo();

        info.Arguments = mageArgs;

        info.FileName = mageExe;

        info.UseShellExecute = false;

        info.RedirectStandardError = true;

        info.RedirectStandardOutput = true;

        Process p = Process.Start(info);


        using (StreamReader stdOutReader = p.StandardOutput)


            string stdOut = stdOutReader.ReadToEnd();

            //Error handling here



        using (StreamReader stdErrReader = p.StandardError)


            string stdErr = stdErrReader.ReadToEnd();

            //Error handling here



This method uses mage.exe to re-sign the application manifest after we’ve modified it using the BuildClientApplicationFile method.  There are two things to note about this method.  You will see that I’m referring to mage.exe from the Visual Studio directory here.  Obviously, installing Visual Studio on servers is not ideal.  Mage.exe also ships separately with the SDKs as indicated in the two articles I’ve linked, which is a more palatable install than Visual Studio.  I have not yet tested to see if mage.exe will properly operate on Windows Server 2003 by itself.

The second note on this method is that we are passing in a fully qualified path to a .pfx key file.  I’ve only tested this using the same .PFX key I used when I initially published the application.

    private static void BuildClientApplicationFile(string path, string signedPath, string key)


        XmlDocument doc = new XmlDocument();


        //Get around the issue of the query string not being persisted by the client

        doc.DocumentElement["deployment"]["deploymentProvider"].Attributes["codebase"].Value += "?key=" +key;



This method stores a special version of the application deployment manifest for this particular client.  I didn’t keep this in memory due to ClickOnce’s odd habit of re-requesting the manifest many times.  This means I’ve got one copy of the manifest per client sitting on my server.  In my testing I’ve found two side-effects for publishing updates using this method:

1)      If I re-activate from the URL and updates have been published, the client does not get prompted

2)      If I run the program from the start menu, the client does get prompted for updates.

Here is the main HttpHandler method:

    public void ProcessRequest(HttpContext context)


        string key = context.Request.QueryString["key"];

        if (ValidateKey(key))


            //Just in case the client doesn't know what to do with .application

            context.Response.ContentType = "application/x-ms-application";


            //The current version deploy URL

            string path = context.Server.MapPath("~/Publish/CarSpot.MyApp.application");


            //Check for existing signed manifest for this user:

            //keeping a specially signed copy of the manifest per client

            string signedFileName = key + ".CarSpot.MyApp.application";

            string signedFileServerPath = "~/Publish/" + signedFileName;

            string signedPath = context.Server.MapPath(signedFileServerPath);


            if (!File.Exists(signedPath))


                //Load the generated deployment manifest as an XML document to make it easier

                //to edit.

                BuildClientApplicationFile(path, signedPath,key);


                string pfx = context.Server.MapPath("~/Publish/MyGeneratedKey.pfx");

                ReSign(signedPath, pfx);

                //Redirect to original path now that we've created a signed one...

                string redirUrl = context.Request.Url.ToString();











            context.Server.Transfer("~/Error.aspx?errormessage=Missing or invalid Application key");



I feel confident this is safe, look at the appref-ms file generated from this install and put in the start menu on the client: /Publish/MyApp.application?key=123#CarSpot.MyApp.application, Culture=neutral, PublicKeyToken=blahblah, processorArchitecture=msil

The key is part of the URL, so it should be passed to the server every time.

Further reading

Now I’ve locked down my deployment manifest, at least you have to have a valid product key to get access to it.  This is a large step towards completely locking down my application.  Since this is ASP.Net code that I control, I can log the remote hosts that use each product key and disable one if it appears to be too promiscuous. 

What about your other files?  If someone somehow figures out that there’s a file called CarSpot.Snark.Zing.dll in the ~/ClickOnce directory?  I have some ideas for this too, along the same lines as what we’ve done here.  You will note that one of the Publish options for ClickOnce is to “Use .deploy file extension”.  Sounds like an HttpModule could be created to handle the .deploy extension.

Microsoft’s behavior regarding ClickOnce baffles me, but here we have a means of securing your deployments.


The Atheists Prayer

by Administrator 17. March 2008 00:06

I found this "atheist prayer" via Friendly Atheist.  I enjoy Friendly Atheist, but I wanted to point out an issue with this post.

"Our brains, which art in our heads, treasured be thy names. Thy reasoning come. The best you can do be done on earth as it is. Give us this day new insight to resolve conflicts and ease pain. And lead us not into supernatural explanations, deliver us from denial of logic. For thine is the kingdom of reason, and even though thy powers are limited, and you’re not always glorious, you are the best evolutionary adaptation we have for helping this earth now and forever and ever. So be it. "

I suppose this is meant as harmless humor, and I probably wouldn't flip out if it had been entitled the Atheist Credo or something similar.  Let's not kid ourselves though.  Equivocation is one of the main ways the un-religious are attacked today.  Sam Harris absolutely called this one right.  To call the extreme skepticism of the possibility of the existance of a god on the same plane as faith is one of the more popular parlor tricks of the faithful today.  To call acceptance of empirical evidence a "kind of faith" turns my FlipOut dial up to 11.  The faithful are having enough of a hayday with ridiculous equivocation arguments as it is.  Do we really need to add ammunition by creating secular versions of old catechisms?  I think not.

Main Entry:
1prayer Listen to the pronunciation of 1prayer
often attributive
Middle English, from Anglo-French priere, praiere, preiere, from Medieval Latin precaria, from Latin, feminine of precarius obtained by entreaty, from prec-, prex
14th century
1 a (1): an address (as a petition) to God or a god in word or thought <said a prayer for the success of the voyage>
Yeah, I think I'll abstain from using this term even in jest, lest it be misconstrued.



by Administrator 15. March 2008 21:45

Dan has posted an excellent article on implementing a Tree structure in C#.  He has beaten me to the punch, after talking about my "Tree of dependent tasks" idea over beers.  I should have something to add to the discussion in the coming weeks.


Downloads will dominate...

by Administrator 14. March 2008 21:37

This is ludicrous talking head speak for the vast overwhelming majority of the movie-watching population.  If I can get better than 1.5mb/s DSL in the next 18 months I'll be shocked, let alone enough pipe to handle True HD video.  At this stage of the market, digital downloads and packaged optical media are NOT different versions of the same product, as these people seem to believe.  They are utterly different products.  38mb/s MPEG4 with 5 mb/s LPCM is not "the same" as the puny bitrates we get through video on demand at this time, and the average consumer can handle having a shelf full of optical discs much easier than they can prepare for terrabytes of digital storage medium.  How many average users have a backup strategy?  The first time you want to watch The Matrix but that hard drive died and you have to redownload you'll be mad.  When you realize the DRM might make re-downloading insanely painful or impossible (as Casey has shown) you'll be wishing you had a Blu-Ray player instead.

The market will figure this out, but not in 12 months, sorry Mr Pundit.

{Edit: I ironically realized after I posted that the words of someone linking to any website with "fanboy" in the name are probably deserving of a side of salt as well.  Oh well, it's the internet...}


Workstation Woes

by Administrator 14. March 2008 16:53

What an astouning letdown: I was on track for a red letter day yesterday.  My parts came in, it was sunny, and I drank some beer and BBQ-ed some poultry.  Hickory smoked BBQ chicken is among my favorite foods and I haven't been able to have it for months because my wife has a pregnancy aversion to most forms of chicken and it's also been ridiculously cold.  I went to best buy and got Bioshock only to discover later that one of my parts is either DOA, I've plugged something in wrong, or the specifications are lying about compatibility.  What a letdown, I expected to be fighting issues like MySQL on 64bit Vista but instead I have no POST.  Luckily my brother recently bought very similar Intel hardware so I should be able swap parts around to find out which piece is dead.  As much as it's a badge of geek honor to build one's own screaming development PC, I think in the future I will not do so during times like now where I have plenty of other things to worry about.


Uncle Damon Again

by Administrator 14. March 2008 16:44

My sister had a little boy at 9pm last night, Daniel James Sapp.  I'm an uncle for the 3rd time in a short while.


About the author

Damon Payne is a Microsoft MVP specializing in Smart Client solution architecture. 

INETA Community Speakers Program

Month List

Page List

flickr photostream