Preventing other websites to see the 'correct' referer - security

On my website users can post stuff anonymously.
When they have posted something they will be redirected to their post, let's say:
http://example.com/post/2/title-of-the-anonymous-post
The user who submitted the post and the admins are the only ones with access to that post (until it is made public). Once it is made public the post would still be anonymous (i.e. people cannot see who submitted the post).
However, on that page there are also some external links. If the user decides to click an external link the target website has the ability to log the http referer (which would contain the link to the hidden page). This means it would be possible to find out who posted it once it is made public.
Is there a way to change the HTTP referer (/ referrer) when a users clicks on a link to another website?
By for example first redirecting the user to another url and let that page redirect to the external website:
user clicks on: http://example.com/referer-hider?url={urlencoded(url)}
and let the referer-hider redirect the user to the external page so that the referer will contain: http://example.com/referer-hider?url={urlencoded(url)}
Will this work? Or is there another solution for this (which doesn't require client side modifications)?

Since the referrer is provided by the browser to a web server, I only see two ways to insure that external sites don't get a view of this "hidden" URL.
First way would be (as you said) to remove the external links from your hidden page by running them through a redirector which uses header("location: ...");). Yes, that will work. You might just want to use this in general, so that you can track the exits from your site.
Second way would be to stop hiding this URL. It won't stay hidden forever, after all. A Google/Alexa/whatever toolbar hits it, and bam, it's indexed. So instead, build this hidden functionality into something session based. Make a script that changes its output depending on session variables, and only allow the hidden content to show up if people have logged in or previewed their post or whatever.
The third (and probably best) way would be to implement proper access control, so that anonymous users CANNOT visit the page with the restricted content. If you want an anonymous original poster to be able to visit THEIR OWN post, you can send them a cookie, then validate the cookie upon the visit to the unapproved post.
For example, upon submission for approval:
setcookie('postkey', mysql_insert_id());
Then:
$pieces=explode($_SERVER['PHP_SELF']);
$postid=$pieces[2]; // or whatever
if (!isset($_COOKIE['postkey'])) {
header("Location: http://example.org/");
} else if ($_COOKIE['postkey'] != $postid) {
header("Location: http://example.org/");
}
etc. You probably want better protection than this, but it should give you some ideas.

The HTTP referer is not transmitted by the browser when a link is going from HTTPS->HTTP. So a simple solution is to have an https redirect page: https://yoursite/redirect?url=... . However this page is also vulnerable to OWASP a10 - Unvalidated Redirects and Forwards, but that might not matter to you. Another solution that doesn't expose you to OWASP a10 is to use a free redirect service.

The Meta referrer proposal from Adam Barth would help with your case; in short you could tell browsers via a <meta> tag that the Referer header should be stripped on all outgoing links.
This isn't a complete answer since it's only implemented in Webkit thus far, but it's something to keep an eye on.

Related

HTTPS iframe within an HTTP page, how can I stop that?

I'm looking at buying an airline ticket, and I'm having to enter my credit card details in a http:// page, that looks like this:
If I look at the source code, this is actually an iframe with an HTTPS source, so this actually secure, but a non-tech-savvy user has no way of knowing that. Obviously, this is horrible (even for tech-savvy users).
Now, my question is, if I was the site offering this iframe (Verified by Visa in this case), is there a way that I could force modern browsers to not allow my page to be used as an iframe on http:// pages, but still allow it to be used as an iframe on https:// pages? Is there a technique that Verified by Visa really should be using here?
I'm looking at buying an airline ticket, and I'm having to enter my credit card details in a http:// page
Ouch! Someone's breaking the PCI-DSS terms of their merchant agreement huh.
If I look at the source code, this is actually an iframe with an HTTPS source, so this actually secure, but a non-tech-savvy user has no way of knowing that.
Indeed. You'd have to look at all the source code, including every piece of script on the parent page, to ensure that there is nothing interfering with the iframe (eg via clickjacking) and that the image you see in the browser page actually is the secure iframe. And ensure there were no other tabs open from the same domain with a reference to the window to cross-document-script into it... a non-starter.
if I was the site offering this iframe (Verified by Visa in this case), is there a way that I could force modern browsers to not allow my page to be used as an iframe on http:// pages, but still allow it to be used as an iframe on https:// pages?
I believe you could do it using Content Security Policy Level 2, eg with the header:
Content-Security-Policy: frame-ancestors https:
However support is patchy: at the time of writing, even the latest IE and Safari don't support it, and obviously it didn't exist at the time 3-D Secure implementations were being written. Still, if it just complains some of the time that would be enough to let an unwitting merchant know they'd messed up their payment integration.
One other thing they might have been able to do back then would be to check the Referer header for an http: address. Still not reliable (and maybe tricky to make work for all possible flows including redirect and pop-up, and in-between redirections) but could have helped.

Is there any way to tell a browser that this is a bad URL to remember?

I'm sending emails to customers, and I'm providing a custom URL for each, which when they go to, will log them in.
This is fine, except if they are using a shared browser that will remember the URL.
Is there any way at all to suggest to the browser that it shouldn't remember a URL?
Edit: This question has nothing to do with caching of the page.
Have the link log them in once. Then make them create credentials that let them access the site in the future. Whats to stop a random person from typing in the url and gaining access to the content?
Yes. You can redirect them with a 301 or 302. Then the browser won't save the URL they went to. At least that work with the Mozilla based browsers and I would imagine others too.
Another way, it is uglier though is to reply with an error and include a body which does a refresh. Whether that works in most browsers, probably not. However, browsers do not cache pages that return an error (404 Page Not Found would work, you could also use 403 Forbidden.)
Other than that, there isn't much you can do. JavaScript does not allow you to temper with the history anymore...

OWASP TOP10 - #10 Unvalidated Redirects and Forwards

I read many of the articles to this topic, including the OWASP PAGE and the Google blog article about open redirects...
I also found this question on open redirects here on stack overflow but it's a different one
I know why i should not redirect ... this makes totaly sense to me.
But what I really don't understand: Where is exactly the difference between redirecting and putting this in a normal <a href link?
Maybe some of the users are looking in the status bar but i think most of them are not really looking to the status bar, when they klick a link.
Is this really the only reason?
like on this article they wrote:
Click here to log in
The user may assume that the link is safe since the URL starts with their trusted bank, bank.example.com. However, the user will then be redirected to the attacker's web site (attacker.example.net) which the attacker may have made to appear very similar to bank.example.com. The user may then unwittingly enter credentials into the attacker's web page and compromise their bank account. A Java servlet should never redirect a user to a URL without verifying that the redirect address is a trusted site.
So, if you have something like a guestbook, where the user can put the link to their homepage, then the only difference is that the link is not redirected, but it still goes to the evil webpage.
Am I seeing this problem right?
From my understanding, it is not that the redirect is the problem. The main problem here is allowing a redirect (where the target is potentially controllable by the user) that contains an absolute url.
The fact that the url is absolute (meaning it begins http://host/etc), means that you are un-intentionally allowing cross-domain redirects. This is very similar to classic XSS vulnerabilities whereby javascript can be reflected to make cross-domain calls (and leak your domain's information).
So, as I understand, the way to fix most of these sorts of problems is to make sure that any redirect (on the server) is done relative to the root. Then there is no way for the user-controlled query string value go somewhere else.
Does that answer your question or just create more?
The main problem is that its possible for an attacker to make the URL appear to be trustworthy as it’s actually a URL to web site the victim trusts, i. e. bank.example.com.
The redirect target does not need to be that obvious as in the example. Actually, the attacker will probably use further techniques to trick both the user and possibly even the web application if necessary with special encodings, parameter pollutioning, and other techniques to spoof a legitimate URL.
So even if a victim is so security-conscious to check a URL before clicking a link or requesting its resource otherwise, all they can verify is that the URL points to the trustworthy web site bank.example.com. And that alone suffices too often.

Implementing HTTP or HTTPS depending on page

I want to implement https on only a selection of my web-pages. I have purchased my SSL certificates etc and got them working. Despite this, due to speed demands i cannot afford to place them on every single page.
Instead i want my server to serve up http or https depending on the page being viewed. An example where this has been done is ‘99designs’
The problem in slightly more detail:
When my visitors first visit my site they only have access to non-sensitive information and therefore i want them to be presented with simple http.
Then once they login they are granted access to more sensitive information, e.g. profile information for which HTTPS is used to deliver.
Despite being logged in, if the user goes back to a non-sensitive page such as the homepage then i want it delivered using HTTP.
One common solution seems to be using the .htaccess file. The problem is that my site is relatively large meaning that to use this would require me to write a rule for every page (several hundred) to determine whether it should be server up using http or https.
And then there is the problem of defining user generated content pages.
Please help,
Many thanks,
David
You've not mentioned anything about the architecture you are using. Assuming that the SSL termination is on the webserver, then you should set up separate virtual hosts with completely seperate and non-overlapping document trees, and for preference, use a path schema which does not overlap (to avoid little accidents).

How to prevent a cross site request forgery attack using an image URL?

From ha.ckers.org/xss.html:
IMG Embedded commands - this works
when the webpage where this is
injected (like a web-board) is behind
password protection and that password
protection works with other commands
on the same domain. This can be used
to delete users, add users (if the
user who visits the page is an
administrator), send credentials
elsewhere, etc.... This is one of the
lesser used but more useful XSS
vectors:
<IMG SRC="http://www.thesiteyouareon.com/somecommand.php?somevariables=maliciouscode">
or:
Redirect 302 /a.jpg http://victimsite.com/admin.asp&deleteuser
I allow users to post images in the forum. How can this be protected against?
I'm using Java Struts but any generic answers are welcome.
If you follow the rules of the HTTP specification, such a kind of attack will make no harm. The section 9.1.1 Safe Methods says:
[…] GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.
Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.
So all requests that change data on the server side should only be allowed via POST. And even there you should only allow those requests that your system has authenticated by generating tokens that are only valid for a specific form/action.
This attack is simply an HTTP GET request made to any URL. You cannot reliably block it by prevent certain <img> tags.
Instead, you need to make sure that your website has no targets (URLs that respond to GET requests and change things)
If there aren't any "juicy" URLs that respond to HTTP GETs (not POSTs) and change data, the attacker will have nothing to attack. (<img> tags cannot be used to create HTTP POSTs)
Cross-site scripting is one reason why you should not allow forum users to post images by linking to images outside your site.
Image posting should be provided by allowing users to upload the image file to your site and using internal relative URI.
By injecting an <img> tag someone can bypass referer based XSRF protection for a GET request. The reason why is because the referer for the GET request produced by the <img> has the same referer as the host its self. So this would bypass code checking to see if the referer and the host where different.
You shouldn't allow people to put html on your page. In this case you should let users upload them and then host images locally. If you really want people to put IMG tags on your site, make sure the URL isn't pointing to your server, because this what an attack would do! Also don't use referer based XSRF protection, use token based. <img> tag injection cannot bypass token based xsrf protection.
No one seemed to mention that the threat in allowing people to post images is not to you, it's to other sites.
If you allow people to post images but your site has no XSRF vulnerabilities, your site is not in danger; other sites with XSRF vulnerabilities are, as your users will unknowingly make requests to the other site via the embedded image when they visit your site. The malicious <img> tag will look something like this:
<img src="http://my-bank-website.com/withdraw_money.php?amount=100000&account=mandy-the-hacker" />
Note that this is not a real image, but the browser will not know that, so it will make the request anyways, transferring $100,000 to mandy-the-hacker's account, assuming the user is currently logged on to my-bank-website.com. This is how XSRF vulnerabilities work.
The only way to prevent this is to force users to upload images, rather than providing URLs for them. However, the malicious user could still just provide a link to the XSRF vulnerability, so removing the ability to provide URLs doesn't really help anything; you are not really harming the other site by allowing <img> tags, they are harming themselves by not using user-specific tokens in forms.

Resources