-1

I'm having some kind of dilemma, I'm writing a JavaScript that posts data from one of my forums to my server where a PHP runs and then decides to output some different JS, depending on the URL the request was made from.

I've been adding a GET parameter to the JavaScript's XHR, but that one could be faked and wouldn't provide the security I'm looking for.

I'm looking for either a superglobal PHP variable that contains the requesting URL (I've looked up the manual but I'm having a hard time comprehending in which way the explanations are meant) or any other way to detect the URL.

Thanks in advance...

  • I can't understand what you want to implement? – Bhavik Shah Nov 13 '13 at 12:45
  • Write down the concrete situation: What are you posting (a new post?), what are you getting back (a js that alerts something?)? This would help to decide the best course of action. – SoonDead Nov 13 '13 at 13:42
  • Updated my answer on what to do. It might be a little long. And I haven't even covered stuff like `JSONP`. – SoonDead Nov 15 '13 at 10:26

3 Answers3

0

You may be looking for $_SERVER['HTTP_REFERRER']

http://php.net/manual/en/reserved.variables.server.php

Be warned as this is not a secure method of determining the validity of the request, but would get the job done.

mulquin
  • 1,341
  • 10
  • 20
0

You should use the superglobal $_SERVER variable. It contains everything you need.

Here is an example of what you need : http://webcheatsheet.com/php/get_current_page_url.php

Damounet
  • 76
  • 1
  • 9
0

What kind of security are you looking for? Preventing the user to forge requests? What can they achieve by forging requests? For example

  1. Can they mess up the site layout for themselves?
  2. Can they access data they should not be allowed to?
  3. Can they write data they should not be allowed to?

If the answer is the first, don't bother with it. They can do pretty much anything on the client side anyway. If you serve incorrect data for a forged request, but they are allowed to get that data in other ways than what is the harm?

The best you can do is to make a restful api for the objects you need, implement a secure user handling, and check for proper user authorization on the object every request. It's cleaner that way and you will not mess it up.

If the answer is the second or third, than you have a problem. A simple superglobal variable will not be sufficient. If you implement some kind of authentication (e.g. like this), and user handling, you will already have your global variable, so your own will be redundant (and less sophisticated). If you have security concerns I assume you already authenticate the user in some way. You can check if the user is authenticated (and authorized to access the content) in an XHR, just like you would check it in a "full" request.


Also guessing the user state from a global variable can harm the usability of your application. Consider this.

  1. User opens 2 similar pages simultaneously both featuring this script. (Tab A and tab B).
  2. Both of these requests set the given superglobal to different values therefore only the second value gets applied. (Let's say that tab A set the value to A, and then tab B set the value to B).
  3. The script from the first tab makes the XHR. It is not what it expects. This is bad. (Since the superglobal is already B it returns the content intended for tab B).

Can you see the problem?


EDIT: Seeing your comment, I'm not yet sure what are your exact scenario and needs. I was able to deduct a few things:

Let's say your domain is good.com and there is an other domain bad.com

Your scenario:

  1. You send a POST (not GET(?)) request by JavaScript (to good.com/posthere)
  2. It returns some JavaScript
  3. I'm not sure what happens to the returned JavaScript, it is perhaps executed somehow, but I have no idea how.

You want to prevent that:

  1. An unsuspecting victim opens a page on bad.com
  2. The page on bad.com makes a POST request to your URL (good.com/posthere)
  3. Sending back the same JavaScript as you would send back to a same-origin request
  4. Browser executing that javascript on the page from bad.com
  5. This tricks the user to thinking he/she is using good.com as he/she is able to chat with the users of good.com

Am I right? Am I mistaken in something? Am I missing something?

There is a big difference between a malicious user sending requests to your site, and a malicious site tricking an unsuspecting user to send request to your site.

For example if the site is malicious there are certain security measures built into the browser, like the Same-origin policy. If the user is malicious, he can do anything he want client-side, circumventing any kind of protection the browsers would offer. He doesn't even need a browser. He could just use cURL and create any request to anywhere.

I will assume that you have unsuspecting users accidentally accessing bad.com instead of good.com.

So what to do?

There are a few things you could do, I will list some that might be suitable in your case. You can use these in combination for more layers of protection.

1. Don't send JavaScript through the wire!

Tempting as it is, sending embeddable resources is an exception to the Same-origin policy built into every modern (and less modern) browser an unsuspecting user might be using. Read the article I have linked about it, read the whole article and read carefully: it explains very important things about this.

The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin

This means it prevents the JavaScript executed on bad.com's site from accessing content from good.com. Just what you would want.

There are a few exceptions however. Anything embeddable might be embedded and than accessed in different ways. For example a JavaScript can be requested and executed(!) with <script src="good.com/js">. This tag can be created by JavaScript.

Of course this is just a GET request, not a POST, but I'm not sure there are no workarounds for POST requests.

Send JSON instead

Sending safe JSON, parsing it with JavaScript and executing client side stuff according to the JSON is a good way to do it.

For example:

var json = '{"isWordfiltered":true,"otherProperty":5}', // this is the response from the server
    obj = JSON.parse(json);

if (obj.isWordfiltered) {
    alert("You wanted to send some bad words. Nobody likes bad words, and therefore nobody likes you!");
}

This requires you to modify your JavaScript code. If you are not a programmer and/or have no knowledge of JavaScript this can be undesirable.

2. Check for the HTTP Referer

HTTP referer (originally a misspelling of referrer) is a HTTP header field that identifies the address of the webpage (i.e. the URI or IRI) that linked to the resource being requested. By checking the referer, the new webpage can see where the request originated.

Hey this also sounds like something that you want! You can check if a request was originated from your page or their page. referer is not from your domain = rejected request. Pretty simple.

You can do this in PHP by accessing $_SERVER['HTTP_REFERER'].

Referers can be forged but this needs some level of user consent (E.G. installing some extension) what a well-meant user will not give. Of course he can actively participate in the attack and do anything, but I have assumed that this is not the case you want to prepare for.

Referers can be disabled in some browsers. This is a bigger concern in your case. Most of the users will have referers enabled, but every once in a while you encounter a user who have disabled it for "security reasons", or have a browser that has referers disabled by default (although this is very rare). Might be a good idea to somehow alert the user (I'm not suggesting the alert() method as it is ugly and intrusive), that he would need to enable the referers.

So

  • if the referer is from your domain, accept the request.
  • if the referer is empty. Tell the user that he should enable the referer.
  • if the referer is not from your domain, reject the request.

One drawback of telling that you want to see the referer is that you tell that you check for it and therefore an attacker might be able to use this information to his advantage. So you might want to do it this (simpler) way:

  • if the referer is from your domain, accept the request.
  • reject the request otherwise

3. (Don't) use a CSRF token to prevent forged posts

You can implement a CSRF token to prevent some forgery, but in your case this is neither sufficient, nor would be easy to implement properly (changing tokens on every subsequential post, etc), so I'm not advising this as a solution only that you read about it.

4. (Don't) use a session token or cookie to see if the user have visited your site

Keep in mind that if you only check for a token that a user have already visited your site and have an active session there, you might set a flag (boolean) in the $_SESSION, or $_COOKIE with short expiration. If the user have not yet visited your site recently, you can deny the request to that javascript.

Although this seems a decent idea, it can easily worked around. For example by an invisible <iframe>.


Keep in mind that after implemening the first and/or the second solution, you might be laying back and thinking that you have won and now your chat is safe.

That is not the case. There are always new attacks, different kind of attacks, etc.

For example if the attacker is a Linux Warlock, he can conjure up a Dark Proxy from Hell on his own webserver and use it to forge everything in the HTTP request. Like this:

  1. He changes the javascript to post to bad.com/proxiedposthere.
  2. The php (or anything else) on server side is written in a manner that it modifies the HTTP header of the request, including the REFERER, and forwards it to good.com/posthere.
  3. Your server sees that it's a valid request, and returns a valid response to his server.
  4. He then modifies the response to his taste (for example switching up all the URL-s in the response to post to their server instead of yours, etc).
  5. He returns the response to the client's browser.

You cannot exactly prevent this. You can ban the IP of the proxy server, but then again the attacker can hide his proxy behind an other proxy. To the infinity.

An example of this is the joke site pornolize.com. It acts as a proxy and switches up a lot of things in a site's text with obscene stuff. It also switches up the links to point to pornolize.com. It's only a childish joke site, but it is a good example of manipulating the response.

The so called web proxies work the same way. They (hopefully) does not manipulate the requests and responses in a harmful way, but they also switch up links.

Community
  • 1
  • 1
SoonDead
  • 6,334
  • 5
  • 49
  • 80
  • I see what you mean. The problem is Number 2, they shouldn't be allowed to access the data. Also, the problem is that the data I'm distributing to the certain URLs is not necessarily copyrighted, but still unique to some forums (which is the other part, not every user should need to authenticate him/herself), so only certain URLs should be allowed to get the data. As mentioned before, not every user has the password. – user2987700 Nov 13 '13 at 13:38
  • You say certain URLs. So basically if a user *knows* a given URL, then he should be able to access the data. If you look at the problem more abstractly, this is exactily the same level of security as you achieved with the get parameter. If you need clarification on this, I can explain it in my answer. – SoonDead Nov 13 '13 at 13:49
  • Also "not authenticating" is also part of the authentication process, there can be parts of an application that an unauthenticated user can access. This is not a contradiction. – SoonDead Nov 13 '13 at 13:52
  • Also "not every user has the password". What password? – SoonDead Nov 13 '13 at 13:53
  • Okay, to clarify, the script that the server returns is a chatbox script for this type of forums I operate with, and because previously, copious codes of our forum had been used without permission, I decided to integrate some server-side validation. The URLs I check come from window.location.host and are unique for each forum, and only those forum URLs should be accepted, so I was looking for a way to undoubtedly verify the origin of the XHR creator. – user2987700 Nov 13 '13 at 17:38
  • So that the problem is that someone stole the code of your site, created a fake one, and he/she is able to embed the same chat as you. Sounds like a these request shouldn't succeed by default, because of the [same origin policy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript). Read articles on cross domain policy and same origin policy. One more question: is the chat on the fake site connects to the same server as the original (people can see each other from both)? – SoonDead Nov 14 '13 at 07:51
  • Please edit your question and elaborate more on the architecture (like site from domain "b" requests abc.xml, server responds with the list of new chat posts, site from domain b then shows post, etc...). A Cross-Site Request Forgery token would likely solve your problem, but depending on the architecture it might be impossible, or easier methods could be sufficient! – SoonDead Nov 14 '13 at 08:17
  • In hindsight I shouldn't have written this much to a question that nobody will ever read. – SoonDead Dec 04 '13 at 23:09