Win8 Metro Style navigation

WARNING! This is based on Developer Preview, and much has changed.

Navigation in Metro is a little fuzzy right now. Fortunately Visual Studio has a navigation template. If you click File.NewProject, and dig into the Metro JavaScript apps, then you will see the Navigation Application. It is described as a “minimal style application that uses Windows Metro style frameworks and includes navigational support.”

The Navigation Template

A look at the source that the Navigation template shows us a pretty contemporary divided-screen model.  It has div that will contain the content, and another one that has the navigation tools.

<body data-homePage="/html/homePage.html">
    <div id="contentHost"></div>
    <div id="appbar" data-win-control="WinJS.UI.AppBar" aria-label="Command Bar" data-win-options="{position:'bottom', transient:true, autoHide:0, lightDismiss:false}">
        <div class="win-left">
            <button id="home" class="win-command">
                <span class="win-commandicon win-large">xE10F;</span><span class="win-label">Home</span>
            </button>
        </div>
    </div>
</body>

The div labeled contentHost will be used to store the content that is directed there. The appbar div is of some more interest. It has a data-win-control property, which is a Metro-specific field that includes specific styles and functionality at render time.

This one is the WinJS.UI.AppBar, which is the little sliding bar that you can access in a Mero app by sweeping from the bottom. There is a 1 pixel trigger left in the bottom of all application that makes the sweep work, and the div shown here sets up the content for the bar.

Right now there is just one button in the bar. If you just click the Debug button without making any changes, you get one button that goes to one page that you already start at. Not terribly interesting.

What that AppBar is supposed to do it give you the ability to load new fragments into contentHost. You can do this with direct buttons, page numbers, or VCR style controls. Doesn’t matter, as long as the content gets loaded.

Loading the fragments is set up in default.js. Remember that weird data-homepage attribute in the body tag of the default page? Well, that’s used to set the initial page in contentHost.

WinJS.Application.onmainwindowactivated = function (e) {
        if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
            homePage = document.body.getAttribute('data-homePage');

            document.body.addEventListener('keyup', function (e) {
                if (e.altKey) {
                    if (e.keyCode === WinJS.Utilities.Key.leftArrow) {
                        WinJS.Navigation.back();
                    }
                    else if (e.keyCode === WinJS.Utilities.Key.rightArrow) {
                        WinJS.Navigation.forward();
                    }
                }
            }, false);

            WinJS.UI.process(document.getElementById('appbar'))
                .then(function () {
                    document.getElementById('home').addEventListener('click', navigateHome, false);
                });

            WinJS.Navigation.navigate(homePage);
        }
    }

After activating the app, a few keyboard events are handled, and then the WinJS.Navigation namespace is used to navigate the page to homepage.

Adding a fragment

One page is really quite boring – why would you need navigation for one piece of content, right? To make things a little more interesting let’s do something wild, like add a page, screen form, wqhatever you want to call it. From Microsoft’s perspective, it is a ‘fragment’ and it is treated like a form or page in any other paradigm.

To add a ‘page 2’ to the template application:

1) In the Solution Explorer, right click on the HTML folder and click Add | New Item…

2) In the Add New Item dialog select the HTML Fragment item and name is Page2.html.

3) After you have added the new fragment, all of the fragment files will be in the HTML folder, as of this writing. Move them into their correct folder. The CSS file goes in the CSS folder and the JS file goes in the JS folder.

4) Update the references in the Page2.html file to point to the new file locations.

<link rel="stylesheet" href="/css/Page2.css" />

<script type="ms-deferred/javascript" src="/js/Page2.js"></script>

5) Update the body content of Page2.html so that we can show some cool neato content when we get there.

<body>
    <div class="Page2 fragment">
        <header role="banner" aria-label="Header content">
            <button disabled class="win-backbutton" aria-label="Back"></button>
            <div class="titleArea">
                <h1 class="pageTitle win-title">Welcome to Page2</h1>
            </div>
        </header>
        <section role="main" aria-label="Main content">
            <p>This is my new page 2! Isn’t it cool?</</p>
        </section>
    </div>
</body>

6) In default.html, add a button that will take the user to page 2. This goes in the appbar div.

<div id="appbar" data-win-control="WinJS.UI.AppBar" aria-label="Command Bar" data-win-options="{position:'bottom', transient:true, autoHide:0, lightDismiss:false}">
    <div class="win-left">
        <button id="home" class="win-command">
            <span class="win-commandicon win-large">xE10F;</span><span class="win-label">Home</span>
        </button>
        <button id="page2" class="win-command">
            <span class="win-commandicon win-large">xE10F;</span><span class="win-label">Page2</span>
        </button>
    </div>
</div>

7) In default.js, you will need an event handler for the new button.   Add it to the process method for the appbar (it’s near the end).

WinJS.UI.process(document.getElementById('appbar'))
    .then(function () {
        document.getElementById('home').addEventListener('click', navigateHome, false);
        document.getElementById('page2').addEventListener('click', navigatePage2, false);
        });
WinJS.Navigation.navigate(homePage);

8) Hey, we need a navigatePage2 method, don’t we? Let’s add that above the process code.

function navigatePage2() {
    WinJS.Navigation.navigate("html/page2.html");
    WinJS.UI.getControl(document.getElementById('appbar')).hide();
}

That should be everything we need. Press F5 to run and (if you are on a regular machine) press Windows+Z to bring up the new appbar. Tap that neat new Page 2 button. And of course here is more to it than this. You might need to keep an array of pages in memory and provide a next/back button, or give random access via a menu. The principles are the same though. Good luck!

Direct Object References

I have to use the Open Graph API from Facebook ton my current project, and I found a real life example of the Direct Object Reference flaw I discuss in my Pentesting ASP.NET talk.

The Direct Object Reference is one of the OWASP Top 10, and is one of the most common security flaws in REST or SOAP APIs. When you use a knowable value as a unique identifier in your response, you are exposing an inportant part of your architecture to a potential attacker, or anyone else who deems your information interesting.

I was suprised to discover that the user identifier for Facebook is an integer. The OpenGraph request for a user looks like this:

https://graph.facebook.com/1138975844

That's me, obviously.

 

{
   "id": "1138975844",
   "name": "Bill Sempf",
   "first_name": "Bill",
   "last_name": "Sempf",
   "username": "billsempf",
   "gender": "male",
   "locale": "en_US"
}

 

By the way, I have every privacy control turned on, and yet anyone can view this basic information. I'm not terribly happy about that.

But who is next in line?

https://graph.facebook.com/1138975845

That could get interesting.

{
   "id": "1138975845",
   "name": "Mary Loaiza",
   "first_name": "Mary",
   "last_name": "Loaiza",
   "link": "http://www.facebook.com/people/Mary-Loaiza/1138975845",
   "gender": "female",
   "locale": "es_LA"
}

Huh.

I wonder how Mary feels about me knowing that she is a facebook user.

Anyway, that's a direct object reference. Keep an eye out for it in your code. It's very simple for an attacker to write a script that checks every number in a range, and get a lot of your database. The easy remiadiation is to use a GUID as the ID, or use the ESAPI AccessRequestMap

 

 

 

 

 

 

Bill Sempf

Husband. Father. Pentester. Secure software composer. Brewer. Lockpicker. Ninja. Insurrectionist. Lumberjack. All words that have been used to describe me recently. I help people write more secure software.

profile for Bill Sempf on Stack Exchange, a network of free, community-driven Q&A sites

MonthList