4

On my MVC3 site, I have a page that contains several links. These links all link back to a route on my site, with different ID values and are structured as such:

ie: www.mysite.com/links/33351/3

I'd like to take advantage of the MVC3's antiforgerytoken mechanism so that I can ensure that all requests to www.mysite.com/links/33351/3 from the link index page.

I'm familiar with how to add the token to a form, however these are all stand-alone links.

How can I accomplish this?

Sergio
  • 6,900
  • 5
  • 31
  • 55
ElHaix
  • 12,846
  • 27
  • 115
  • 203

3 Answers3

3

You can't use the AntiForgeryToken for GET requests (i.e. clicking a link). For details - see Using MVC3's AntiForgeryToken in HTTP GET to avoid Javascript CSRF vulnerability.

One solution is to check the Request.UrlReferrer to ensure they came from your index page, but this is far from reliable.

Perhaps you could explain why you want to impose this restriction and I may be able to propose an alternative.

Community
  • 1
  • 1
Ben Foster
  • 34,340
  • 40
  • 176
  • 285
  • Ben, We have noticed several site scrapes, which we have put measures in place to reduce. However, when someone has a scrape of our site, we don't want the crawling to these links unless the requests originated on our server. Navigating to the link performs some maintenance then continues on to the link. I realize the AntiForgeryToken does not work for GET requests, so something like creating a form, on the page, instead of hard links, invoke some JS to populate the fields that need populating then send the form with those values. Any other suggestions? – ElHaix Dec 30 '11 at 15:16
  • @ElHaix - A GET request should not alter state. Therefore, if clicking these links performs some maintenance on the server, you should change these to form POSTs. This way scrapers and search engines alike will not invoke the links. Trying to ensure pages are navigated internally is going to cause you a headache. – Ben Foster Dec 31 '11 at 14:50
2

Thanks to the comments above which helped me solve this.

Essentially, I created a Javascript function to process the item clicks. Each link on my page has an ID, so I simply passed the ID through to the JS function which submits the form:

<script type="text/javascript"> <!--
    function doClick(itemID) {
        document.getElementById('hid_ItemID').value = itemID;

        // add whatever additional js type processing needed here - ie. analytics, etc.

        document.forms[0].submit();
    }
//-->
</script>

The form itself contains the MVC anti-forgery token tag:

@using (Html.BeginForm("DoRequest", "DoItemClickRq", FormMethod.Post, new { target = "_blank" }))
{
    @Html.AntiForgeryToken()
    <input type="hidden" id="hid_ItemID" name="hid_ItemID" value="" />
.
.
.

The controller method:

    [ValidateAntiForgeryToken]
    [HttpPost]
    public ActionResult DoItemRequest()
    {
        int itemListID = 0;
        int pagePositionNumber = 0;
        int.TryParse(Request["hid_ItemID"], out itemListID);

. . .

ElHaix
  • 12,846
  • 27
  • 115
  • 203
0
  1. For good design practice, all URLs in your application accessible via HTTP GET should be idempotent, meaning they should not change state no matter how many times they are accessed. It sounds like this may be the root of your problem, depending on the interpretation of "Navigating to the link performs some maintenance". Or you may be concerned about system load due to the maintenance. That is one reason why CSRF approaches have typically avoided handling GET requests.
  2. Exposing CSRF tokens in URLs, like session IDs, is bad security practice. URLs can leak into logfiles, proxy servers, especially if your site doesn't use 100% SSL.

Are the web crawlers standard well-behaved ones? If so, why not just use robots.txt to constrain the crawling behavior?

If that is not sufficient, perhaps you need to impose some sort of workflow restriction to prevent deep-link access (e.g. access to link X with session id A without going through steps 1 and 2 first is denied by your controller).

core24
  • 111
  • 6
  • I can see the standard web crawlers and they are well behaved - adhering to my noindex/nofollow decorators. However I can see that from the scraping attempts that they are just trying to soak up all of our content. While linking to our sites, and bringing traffic to certain pages is good, others, we want the traffic to originate on our sites. The maintenance is simply some click tracking code, then the user is brought to the page. The session approach may be a good quick fix rather than Javascripting a new form post solution. – ElHaix Dec 30 '11 at 16:11