The website of UK supermarket chain ASDA is in the news for all the wrong reasons today.
A security researcher, who claims to have waited 677 days after first telling the company about various security problems on the site, has ultimately gone public with his findings.
Fortunately, even though Paul Moore published a video to prove his point, he didn’t go public with a “how to” guide, or with sample code that would allow wannabe hackers to abuse ASDA’s site at will.
So, with the holes apparently now fixed, Moore seems to have achieved peace with honour.
Of course, if you run a website of your own, or your company does, or someone else runs a website for you, you probably want to make sure that you don’t fall into the same sort of holes that ASDA did.
According to Moore, the flaws in ASDA’s site were amongst the most common sort of web programming mistakes, namely XSS (Cross Site Scripting) and CSRF (Cross Site Request Forgery).
If you’re a techie, you can read up on these issues – and how to keep them under control – on the OWASP website.
If you aren’t a techie, here’s a brief explanation, as simply as we can manage.
Websites often take user-supplied content that arrives in a web request from outside, and use some or all of that content in their reply, for example during searches.
Suppose I search for “facetiously” by submitting a URL like this:
If that word doesn’t appear on your site, you might send back something like this:
But if I were a crook, I might search for something hostile instead, such as:
Whereupon your web server needs to be very careful not to reply with:
If you were to send that reply, you would effectively be publishing my script as a trusted part of your site, even though you’d never seen the script before in your life, let alone passed it through code review, testing and quality assurance.
That means my script essentially “crosses over” to your site, where it can access data specific to your web property, such as login cookies and other personal data that isn’t supposed to be visible to me.
CROSS-SITE REQUEST FORGERY
Websites often trigger commands – for example, form submissions such as “approve this payment” or “update saved email address” – using special URLs, for example:
Obviously, this sort of URL-triggered web command needs some sort of protection, or else I could hijack your email by publishing a URL like this somewhere on my site and then trying to persuade or to trick you into clicking it.
I’d effectively be flying blind, because I wouldn’t be able to see the outcome of clicking the link – if there were any reply, it would appear in your browser.
Indeed, you might realise that something had gone wrong, because you might see an unexpected popup from the id.example.com site.
For these reasons, CSRF isn’t generally quite as dangerous in the hands of a crook as a full-blown XSS vulnerability – the crook can trigger certain specific requests, but can’t run arbitrary scripts.
Nevertheless, it shouldn’t be possible for one site to use a pre-constructed URL to “cross over” and issue commands on another site.
Note that our often-repeated advice to “logout when you aren’t using a site” helps prevent CSRF attacks. A fraudulent link on site X that is supposed to to trigger a CSRF action on site Y won’t work if you aren’t currently logged in to site Y. You’ll just get a “not logged in error,” or see an unexpected “please login” dialog pop up instead.
Typically, CSRF attacks can be avoided by making all your web forms unique, for example by including a random, one-off transaction number in a hidden field in every form, so I would need to guess this uid or nonce (unique identifier or number used once) to succeed:
Because the unique identifier is different every time, my CSRF attack would need a new URL every time, and unless I could somehow read the contents of your browser windows first and extract the identifier, I’d be unable to construct a CSRF URL that would work.
Note that XSS attacks usually do allow crooks to read cookies and content from web pages already displayed in your browser, so XSS and CSRF can be combined. XSS is used to bypass the “nonce” protection against CSRF; and then CSRF is used to hijack an account, approve a fake payment, or something of that sort.
WHAT TO DO?
• If you are worried about the data from one web session leaking into another, clear all cookies and saved web data, restart your browser, and conduct your sensitive transactions in a single tab, in isolation. Data such as page content and login cookies can’t be accessed from another browser tab or window if there isn’t one!
• If you are a web programmer, validate any data you receive from outside very carefully. Anyone who tries to send you a username that is a disguised version of the text string <script> is up to no good!
• If you are a web programmer, make each web form unique at run time, for example with a nonce. That way, an that an attacker can’t guess how to construct valid web requests simply by looking at previous sessions.
Oh, and we’ll say it again, because we can: “Logout when you’re done. Yes, even from Facebook!”
6 comments on “Supermarket patches its web security…how safe are *your* web forms?”
Paul, thanks for the great explanation of CSRF.
Umm, Duck, you forgot the after “found.”
Help! I can’t find the word “found” to find what I forgot after it 🙂
Arrrgh. The reply editor deletes anything it thinks might be HTML and hence mangled my comment. And you put your HTML examples in bitmaps causing its text to be unsearchable. Let’s try again.
You wrote (in the pink-background example):
<p>Sorry: <em>facaetiously</em> was not found.
After the last word, “found.” there should have been </p>
Duck’s HTML is actually perfectly valid. Closing tags on P elements have always been optional under certain fairly broad conditions in HTML. They were only mandatory in XHTML 4 because it’s an application of XML which demands that all non-empty tags be closed.
In HTML 4 and HTML 5 the rules are: “A p element’s end tag may be omitted if the p element is immediately followed by an address, article, aside, blockquote, div, dl, fieldset, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, main, nav, ol, p, pre, section, table, or ul, element, or if there is no more content in the parent element and the parent element is not an a element.”
In this case the P element is the last child of the parent element.
As far as I am aware, the paragraph tags in those examples do not require closing slash-p markers, and IMO clarity is improved by omitting them.
Those paragraphs very obviously end when the HTML body ends and so just having the slash-body marker is perfectly clear on its own, whatever XHTML purists might say.