November 03, 2008

Hidden fields vs. CSS

Intro

A hidden field is supposed to be hidden - invisible for the user as long as he uses an unmodified browser and isn't watching the sources via view-source: or similar. Not to forget the agnostic regarding mouseover, error, load, focus and other events. So for example if an attacker manages to inject content into one of the hidden field's attributes and can't break out the attack window is very small.

Some markup

So it's not very surprising that most user agents treat a hidden field as hidden - no matter what styles have been applied to the element. The following code should thus result in a plain white page without any visible elements or even event handlers waiting for interaction.

<html>
<head>
</head>
<body>
<form action="#">
<input type="hidden" id="hidden" value="secret!" />
</form>
</body>
</html>
<style>
input[type=hidden] {
 display: block;
 height: 100px;
 border: 2px solid red;
}
</style>
<script>
document.getElementById('hidden').onmouseover = function(){
 alert(this.value);
};
</script>

And yes - all browsers show a white page - IE6-8, Chrome, Opera, even Safari. Only Firefox shows a big red bordered bar which responses with an alert when hovered with the cursor. The element can even be selected via CSS pseudo classes.

<html>
<head>
</head>
<body>
<form action="#">
<input type="hidden" id="hidden" value="secret!" />
</form>
</body>
</html>
<style>
input[type=hidden] {
 display: block;
 height: 100px;
 border: 2px solid red;
}
input:hover {
 border: 2px solid green;
}
</style>

Of course it's also possible to extract password field values with that technique

<html>
<head>
<style>
input {
 a:expression(alert(this.value));
}
</style>
</head>
<body>
<form action="#">

<input
 type="password"
 value="secret!"
/>
</form>
</body>
</html>

Opera by the way provides a very special way to extract passwords in clear text - with the :after or :before pseudo classes and the attr() value for the content property.

<html>
<head>
<style>
input[type=password]:after {
 content: attr(value);
}
</style>
</head>
<body>
<form action="#">

<input
 type="password"
 value="secret!"
/>
</form>
</body>
</html>

We are losing track with the password fields - and will be talking about them in a later article anyway so back to the hidden fields.

In IE6-8b2 you can of course inject expression() CSS - but the CSS selector input[type=hidden] doesn't work. So surprisingly it's possible to select just input and filter the hidden fields in the expression statement afterwards with just input as selector.

Conclusion

IE6-8 allow to select hidden input fields with CSS and bind JavaScript code. That's not very nice but possible to coexist with. Firefox on the other hand really shows how not to do it again. Making hidden fields visible with CSS is definitely crossing a border - at least the one between data and presentation.

It's also possible in FF3 to select hidden fields via CSS - be it with input[type="hidden"], input[type^="hid"], input[type$="den"], input[type|="hidden"] or even input[type~="hidden"].

And just by the way - this shouldn't be possible either:

<html>
<body>
<form action="#">
<input type="hidden" id="hidden" value="secret!" />
</form>
</body>
</html>

<label for="hidden">Click</label>
<script>
document.getElementById('hidden').onclick = function(){
  alert(this.value);
};
</script>

No comments:

Post a Comment