This area is really complex and it's clear from some of the comments that not everyone has managed to get their head around it. Let's see if I can.
Here I manage to "inject" malicious code into a web page in various ways. The simplest means by which this can happen is that I find a site that "reflects" back my user input onto the page (say a search page the provides me with a display a bit like this):
Now if I don't handle this correctly (as a site developer) and someone enters some script that I simply reflect back onto the page, we have an exploit. Eg Say I send someone a (suitably disguised) link like this: http://search.live.com/results.aspx?q=<script>alert('Do%20something%20nasty%20here')</script>. They click on it. My code executes to grab as much of their data as it can and send it back to me. Nyahahahahar (sinister laugh).
(Note that Live Search does handle it correctly - see below - ie my script wont execute on their page).
There are other variants - a particularly ugly one involving the storage of my user-entered data somewhere (say in a user profile). Now, if my user-entered data isn't correctly filtered before being re-displayed to other users who view my profile, I can have a field day.
Defending against this involves validating user input and filtering any input you use as output. I talked about HTML encoding previously, but Ben rightly highlighted the use of the ASP.NET Anti-Cross Site Scripting Library which uses the principle of inclusion to allow "good" things in the user input and disallow (encode) everything else. For more details see the further reading on this blog post.
The general idea here is that I, malicious person that I am, include an HTML tag on my page such as:
or even an image tag with the same sort of form such as this:
Now this requires a number of things in order to work - a site that relies on a users identity and issues some sort of cookie as a form of authentication (hence this type of attack is also known as "session riding"). A user that has a current session (or a persistent cookie) with that site. And a site that doesn't require any specific authorisation for the action I (as the malicious user) am about to perform. So lets lower our standards a bit (let's *assume* - dangerous - that most online banking sites wont fit those criteria) and aim for say modifying someone's profile, adding them as a friend or perhaps adding my blog to your technorati / del.icio.us favourites (I'm not suggesting those sites are vulnerable!). How about I play havoc with your webmail? You get the idea.
Defending against this as a web developer (as opposed to a user) typically involves additional authentication steps (eg when I do a monetary transfer at my bank I get asked to re-enter my password) or using some hidden field with a (difficult to guess) server generated value that is re-checked when the form is posted to the server. There is no way for the attacker to get hold of that secret value so the server can differentiate between legitimate and forged requests. And always use Http POST for this type of request (as GET is intended for safe operations with no side-effects).
Now combine CSRF with JSON; hijacking attempts to "fool" the server into serving up some confidential data as JSON which I can then manipulate on the client side - ie send up to my own server to do with what I will. Mike points to this article at Fortify Software which describes the technique in some depth. The good news is that ASP.NET AJAX has some built-in security against these techniques - specifically the ASP.NET AJAX web services layer will only respond to POST requests unless you specifically override this behaviour. In addition, we look for the content-type "application/json" in the request header - if it's not found, the request is rejected. See Scott's post for more details.