4

I am currently working on a script that website owners could install that would allow users to highlight a word and see the definition of the word in a small popup div. I am only doing this as a hobby in my spare time and have no intention of selling it or anything, but nevertheless I want it to be secure.

When the text is highlighted it sends an AJAX request to my domain to a PHP page that then looks up the word in a database and outputs a div containing the information. I understand that the same-origin policy prohibits me from accomplishing this with normal AJAX, but I also cannot use JSONP because I need to return HTML, not JSON.

The other option I've looked into is adding

header("Access-Control-Allow-Origin: *");

to my PHP page.

Since I really don't have much experience in security, being that I do this as a hobby, could someone explain to me the security risks in using Access-Control-Allow-Origin: * ? Or is there a better way I should look into to do this?

5 Answers5

2

Cross-Origin Resource Sharing (CORS), the specification behind the Access-Control-Allow-Origin header field, was established to allow cross-origin requests via XMLHttpRequest but protect users from malicious sites to read the response by providing an interface that allows the server to define which cross-origin requests are allowed and which are not. So CORS is more than simply Access-Control-Allow-Origin: *, which denotes that XHR requests are allowed from any origin.

Now to your question: Assuming that your service is public and doesn’t require any authentication, using Access-Control-Allow-Origin: * to allow XHR requests from any origin is secure. But make sure to only send that header field in those scripts your want to allow that access policy.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
1

JSONP should fit your needs. It is a widely deployed web technique that aims to solve cross domain issues. Also you should know about CORS which addresses some disadvantages of JSONP. The links I gave you will also contain information about security considerations about these techniques.

You wrote:

but I also cannot use JSONP because I need to return HTML, not JSON.

Why not? You could use a JSONP response like this:

callback({'content':'<div class="myclass">...</div>'});

and then inject result.content into the current page using DOM manipulation.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
1

"When the text is highlighted it sends an AJAX request to my domain to a PHP page that then looks up the word in a database and outputs a div containing the information. I understand that the same-origin policy prohibits me from accomplishing this with normal AJAX, but I also cannot use JSONP because I need to return HTML, not JSON."

As hek2mgl notes, JSONP would work fine for this. All you'd need to do is wrap your HTML in a JSONP wrapper, like this:

displayDefinition({"word": "example", "definition": "<div>HTML text...</div>"});

where displayDefinition() is a JS function that shows a popup with the given HTML code (and maybe caches it for later use).

"The other option I've looked into is adding header("Access-Control-Allow-Origin: *"); to my PHP page. Since I really don't have much experience in security, being that I do this as a hobby, could someone explain to me the security risks in using Access-Control-Allow-Origin: *?"

The risks are essentially the same as for JSONP; in either case, you're allowing any website to make arbitrary GET requests to your script (which they can actually do anyway) and read the results (which, using normal JSON, they generally cannot, although older browsers may have some security holes that can allow this). In particular, if a user visits a malicious website while being logged into your site, and if your site may expose sensitive user data through JSONP or CORS, then the malicious site could gain access to such data.

For the use case you describe, either method should be safe, as long as you only use it for that particular script, and as long as the script only does what you describe it doing (looks up words and returns their definitions).

Of course, you should nor use either CORS or JSONP for scripts you don't want any website to access, like bank transfer forms. Such scripts, if they can modify data on the server, generally also need to employ additional defenses such as anti-CSRF tokens to prevent "blind" CSRF attacks where the attacker doesn't really care about the response, but only about the side effects of the request. Obviously, the anti-CSRF tokens themselves are sensitive user-specific data, and so should not be obtainable via CORS, JSONP or any other method that bypasses same-origin protections.

"Or is there a better way I should look into to do this?"

One other (though not necessarily better) way could be for your PHP script to return the definitions as HTML, and for the popups to consist of just an iframe element pointing to the script.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
0

CORS issues are simple - do you want anyone to be able to remotely AJAX your stuff on your domain? This could be extremely dangerous if you've got forms that are prone to CSRF. Here is an example plucked straight out of my head.

The set-up:

  • A bank whose online banking server has CORS headers set to accept all (ACAO: *) (call it A)
  • A legitimate customer who is logged in (call them B)
  • A hacker who happens to be able to make the client run anything (call it E)

A<->B conversation is deemed lawful. However, if the hacker can manage to make the mark (B) load a site with a bit of JS that can fire off AJAX requests (easy through permanent XSS flaws on big sites), he/she can get B to fire requests to A by JSON, which will be allowed and treated as normal requests!

You could do so many horrible things with this. Imagine that the bank has a form where the input are as follows:

POST:
* targetAccountID -> the account that will receive money
* money -> the amount to be transferred

If the mark is logged in, I could inject:

$.ajax({ url: "http://A/money.transfer.php"; data { targetAccountID: 123; money: 9999; }; });

And suddenly, anyone who visits the site and is logged in to A will see their account drained of 9999 units.

THIS is why CORS is to be taken with a pinch of salt - in practice, DO NOT open more than you need to open. Open your API and that is it.

A cool side note, CORS does not work for anything before IE9. So you'll need to build a fallback, possibly iframes or JSONP.

I wrote about this very topic a short while back: http://www.sebrenauld.co.uk/en/index/view/access-json-apis-remotely-using-javascript in a slightly happier form than Wikipedia, by the way. It's a topic I hold dear to my heart, as I've had to contend with API development a couple of times.

Sébastien Renauld
  • 19,203
  • 2
  • 46
  • 66
  • CORS does not prevent CSRF. The primary intent of CORS is to give the server to choice which origins are allowed to send requests and to read the responses. – Gumbo Apr 06 '13 at 17:53
  • @Gumbo: Thank you for echoing my point. I never said that CORS prevented CSRF - what I said is that, if badly set up, CORS can turn POST requests into valid CSRF targets (something which is very rare otherwise). – Sébastien Renauld Apr 06 '13 at 17:54
  • Actually, "simple" POST requests (such as can be generated by submitting an ordinary HTML form) are vulnerable to CSRF anyway, with or without CORS. To prevent that, you need something like anti-CSRF tokens. Also, -1 for not actually addressing the OP's intended use case. – Ilmari Karonen Apr 06 '13 at 17:58
  • @IlmariKaronen: They require user input. This one does not, which makes it dangerous. Also, what exactly did I not address? CORS allows him to do a regular AJAX call across domains to fetch HTML if he wants to - that was never the problem. He asked for the security risks, and I gave him exactly that: if badly set, he opens up his entire directory/arch to remote HTTP POST requests that could be phantom. What exactly did I miss, if you'd like to point it out? – Sébastien Renauld Apr 06 '13 at 18:01
  • There's no user input required, it's easy for client-side JS to construct and `.submit()` an invisible form (possibly in an iframe) without the user even noticing. As for what you missed, the OP asked whether it's safe to use `Access-Control-Allow-Origin: *` for a script that looks up and returns definitions of words. You told them that it's _not_ safe to use it for a script that performs bank transfers. Those are not the same thing. – Ilmari Karonen Apr 06 '13 at 18:06
  • @IlmariKaronen: I stated, and I will quote: "in practice, DO NOT open more than you need to open. Open your API and that is it.". In other words, open whatever script you want with CORS, but do not open more than you absolutely need to. As for the `.input()`, the risks are still not quite as big: if you're firing it in the main window, the person notices. If you fire it in an iframe, you can't get the return value of the call, whereas you can with CORS-calls. – Sébastien Renauld Apr 06 '13 at 18:10
  • That's certainly good advice, but if I were the OP, and did not know the answer already, I'd certainly find it hard to read between the lines in your answer to tell whether it actually is or isn't safe for me to use CORS in this particular case. (As for submitting a form in an iframe... well, it's enough to carry out the exact same attack against your hypothetical money transfer script that you describe in your answer above, even without CORS.) Anyway, should we continue this in chat? – Ilmari Karonen Apr 06 '13 at 18:16
0

Concept of CSRF(Cross Site Request Foregery) can be your concern http://en.wikipedia.org/wiki/Cross-site_request_forgery there are multiple ways to limit this issue, most commonly used technique is employing use of csrf token.

Further you should also put a IP based Rate limiter for "Limiting execution of a to number requests made from a certain ip", to limit DoS attacks that can be done if you are a target, you can seek some help from the How do I throttle my site's API users?

Community
  • 1
  • 1
akm
  • 79
  • 2