48 comments

[ 2.4 ms ] story [ 96.0 ms ] thread
Seems fairly clear that this is a Django issue, not a Bitbucket issue. Maybe change this link to point to the equivalent Django bug: https://code.djangoproject.com/ticket/16870.
Of course it's a 100% Bitbucket issue as seen as a user. I ran into the same issues while having some debug headers set.

As a user I simply don't care what platform they use.

So when my car breaks down I should expect Toyota to say "sorry that's a Takata issue take it up with them"?
But that's not what happened here at all. Bitbucket has responded explaining why this (self-inflicted) bug exists (a security decision in an underlying framework) and deferred to the framework maintainers for further discussion because they have the best context on why that decision was initially made and under what scenarios it might be changed.
They chose to use a framework without understanding the implications of its security issues. When one comes up, they tell their users it's someone else's problem. Maybe they're an impoverished company that can't afford to pay to solve the problem. Or they dont care much.
It is an open source framework. They are free to patch the code.
A better analogy is you pump 100% ethanol into your gas tank, a sensor shuts it down, and you tell Toyota "This is actually perfectly safe for the engine for these reasons, here's why the engine manufacturer's safety document is wrong." I'd hope Toyota understands engines enough to have the ability to argue with you if they choose, but "The interlock is from the engine manufacturer and we're not going to overrule their judgment, please convince the engine manufacturer to remove the interlock" is a fine answer.

After all, you could just pump normal fuel into your car, which does have harmful side effects but it's also what everyone does. It's not like the current situation makes your car inoperable or unsafe.

Bitbucket should not POST from HTTP to HTTPS. It's their issue to fix.
Well, you should not post from HTTP to HTTPS anyway.

I highly doubt there is any good reason to do it anywhere, and on the one case you think you got a good reason (I still doubt it), don't try to anonymize the hell out of a logged-on request.

From memory when this came up, I think the concern is someone spoofing a non-HTTPS version of your site to trick a browser into posting to the HTTPS version? Someone that understands this stuff properly will need to chime in.
It looks like Django relies on client-side tokens embedded in cookies for CSRF protection, there is no server-side state that the attacker has to guess. A MITM can trick someone to visit http://example.com/, set their own token in a HTTP cookie for example.com, use the same token in the POST request to https://example.com and it will pass validation, as cookies set over HTTP are still sent to HTTPS.

Should be easy to mitigate this by using server-side CSRF state, or signing the tokens.

I'm a bit confused... I thought that Django always signed the CSRF tokens with the app's SECRET_KEY

But upon looking at the code, it seems that the SECRET_KEY is only used to reseed the PRNG O_o

https://github.com/django/django/blob/stable/1.10.x/django/u...

Unfortunately the csrf implementation doesn't use that. (At least not in the absence of a session store.) It "encrypts" the random token by adding a random salt to it, but has no way of validating that after generation. When a csrf protected request is made the token in the cookie is compared to the token in the POST data, but not validated in any other way.

https://github.com/django/django/blob/master/django/middlewa...

I wonder how much of this is just a political issue about the core/contrib division and the fact that csrf is in core while sessions is in contrib. It seems to me that the "right" fix is to make csrf protection require a session store, and move (at least) the signed cookie session support into core.

Edit: Actually it looks like cookie signing is already implemented in core, so now I'm really unsure why csrf isn't using that already.

Yeah, weird... I guess that since sessions are enabled by default, they didn't bother making it independent/explicitly requiring it
I think this choice was made because Django doesn't _require_ sessions to be used. So they're making a compromise that could (however marginally) improve security regardless of the configuration of the site.

I think perhaps some way of saying "I use sessions, and therefore CSRF should rely on that" could be reasonable, but with security stuff like this I'm really hesitant to say that more definitively.

"there is no server-side state that the attacker has to guess"

That part is certainly true when django isn't using sessions.

I think that in normal use the tokens are still always generated on the server, not the client, though. The problem is that like you said, there is no way to validate that without some server state, so even though the server is expected to have generated the token, it can't distinguish and invalidate a token generated by anyone else as long as it's in the correct format.

Looks like it

https://security.stackexchange.com/questions/96114/why-is-re...

I don't think that the solution can be as simple as:

> you should not post from HTTP to HTTPS anyway.

because if the attacker is MITM'ing your user, he can supply the user a HTTP page that you never created (unless you have HSTS enabled)

The obvious inquire: "why doesn't the attacker simply steals the login cookie?", can probably be simply explained if your service is setting the Secure flag in the Set-Cookie header (as it should)... this way, even if the victim is logged in, the attacker wouldn't be able to steal the cookie

I don't think that "the site does not work while somebody is phishing my connection" is a valid complaint.

One should indeed protect against malicious HTTP pages, HSTS is a good thing, browser warnings on HTTP is an even better thing. But there is no reason to put any effort on avoiding a 403 error on those cases.

You misunderstand the problem. Referer is checked to prevent forged POST requests from HTTP to HTTPS, not to avoid a 403 error.
My point is that you should never POST from HTTP to HTTPS. So anytime that this happens, Django developers are more than justified on issuing any error they want and marking them wontfix as they wish.
Does anyone know of a good alternative to the atlassian suite? Given their price structure and popularity, I'd expect them to fix stuff like this in a timely fashion, and fix some basic UI issues.

Bitbucket server (aka "stash") examples:

- Create a pull request (the most common workflow in bitbucket) takes far too many page loads, and is buried in "hamburger"/"more options"

- For teams with per-developer repos, it does not remember which repos the currently logged in user frequently uses, so you scroll through everone on the team's name for most operations. (And the new version "improved" this in some places with a JavaScript-heavy list that renders like molasses on no-gpu xeon vms).

- Each product (bitbucket, jira, confluence) uses a different markup language.

And so on. I could complain about other workflows or other products, but this is pretty typical for their stuff.

I would be interested to know as well. To add to your list. If you need to scale up to huge intsances it hurts. Repo Clones take huge amount of resources for some reason, and updates require hours of downtime to spin the cluster up again. Aparrently there development team haven't even had a very large instance for test until late 2016 so fixing there issues is likely to take time.
Bitbucket product manager here.

Sorry to hear you've been having trouble. What you describe is most definitely unusual so I'd suggest contacting us (or having your admin contact us) at support.atlassian.com so we can look into it.

The team has spent a great deal of effort over the entire life of the product to ensure it performs at scale for broad range of load profiles. The notion that we only recently had a very large instance for test is untrue. Perhaps someone got the wrong idea from our most recent series on how we build Bitbucket Data Center to _already_ support massive scale: https://developer.atlassian.com/blog/2016/12/how-we-built-bi...

sounds exactly like jira and bamboo

an empty jira instance on hardware meeting their recommended spec used to take 3+ minutes to start up

For the source code management, you can try rhodecode. There's a community version too.
Normally, I create a pull request using the server response from git on the command line - Bitbucket replies with a URL to create a PR. In fact I have a git alias, 'git gone', which pushes, parses the response looking for the URL and launches it in my browser.

Per-developer repos are definitely an anti-pattern for Bitbucket usage. They just don't work well; it's all too easy to have a half-dozen slightly different versions of a branch in different people's repositories. It's generally better to use your local repo for your personal branches, and use a single repo on Bitbucket for team interaction. There's definitely a risk of data loss if it's not otherwise backed up, of course.

My personal bugbears are mostly relating to Jira. It needs a better mechanism for integrating estimated & actual numbers for predicting velocity. The only mechanism it natively supports is story points, and it's not enough. You often want to break down stories, but the hierarchy really doesn't work well. You can't put numbers on a finer granularity than stories.

It also doesn't work at a higher level, when developing a road map. It's just kind of stuck in the middle.

Jira is in many ways the "hub" of the Atlassian eco system and I'm hard pressed to find an alternative that will integrate with so many other products. If it's just Bitbucket you dislike, then you could just sign up for Github. The rest of the Atlassian suite isn't that tied to Bitbucket.

I worked for a company that used Confluence and Jira with Github and I now work for a company that have a self hosted Bitbucket, the integrations are equally good (in my opinion).

It isn't until you try to replace Jira you'll run into problems.

I'm a product manager on the Bitbucket team.

For the first issue you mention, it sounds like you might be using an older version as this has been improved in a couple of respects in the last few releases. Specifically, the create pull request menu item (and it's siblings) are no longer collapsed in the sidebar. There is also a create pull request button on the pull request list page, and recently updated branches have a create pull request button on the personal dashboard shipped in Bitbucket Server 4.10.

Regarding frequent repos, I'm not entirely clear on where you're encountering this issue. If you send a screenshot to rbarnes atlassian com (spaces -> at, dot) I'll be happy to follow up with the team. We have some repo findability improvements in the works so it's a good time to make sure we haven't missed a pain point.

On the markup front, I hear ya. History makes it a little tricky to resolve in a way that will satisfy all, but we're looking at where editor UIs can converge to.

Relying on the referrer header for CSRF protection is dubious at best. Just use a token like everybody else, protect against session fixation, call it a day.
They are using a token, just like everyone else... this is just some added protection on top

Let's not spread FUD :)

It's not really any additional protection...how are you going to break a token? I've encountered this a few times on other sites, have to waste a few seconds messing around in my about:config.
But this isn't added protection. Here is the textbook list of security goals:

- availability

- integrity

- confidentiality

It breaks availability and confidentiality to protect against an attack that is already prevented by https.

This is like installing an open ip cam and welding my padlock shut, then claiming you've improved my storage unit.

Have you read the discussion on security.stackexchange.com ?

there's no decrease in availability by an attacker (there's only a self inflicted denial by the user)

there's also no decrease in confidentiality for the service itself (and if the user uses an appropriate extension[0], or the browsers implement an appropriate whitelist mechanism, there's no confidentiality decrease for the user in general either)

This is simply defense in depth

If you leaked the SECRET_KEY/misconfigured the CSRF creation (which should be impossible, but it's the whole point of adding layers) AND the victim is being MITM AND you don't implement HSTS AND You correctly set cookies as Secure

You would have a potential vulnerability, exploitable (only?) via CSRF, which this check prevents

[0] like https://addons.mozilla.org/en-US/firefox/addon/smart-referer... but I'm not advocating for the use of this extension

So redirecting all port 80 requests to https://<domain>/ (or otherwise kill port 80 on the server).

Then, make sure each page view overwrites / clears any side-effecting session state.

Put another way, why should unexpected cookies change the side effects of post requests?

Anyway, if the browser is connecting via port 80, the MITM can just use a transparent http->https proxy to rewrite the referrer, and forward the request to the https server, so you've already lost.

I think you're misunderstanding the attack scenario here:

> Anyway, if the browser is connecting via port 80, the MITM can just use a transparent http->https proxy to rewrite the referrer, and forward the request to the https server, so you've already lost.

That wouldn't actually work since the user's active session cookie has the "Secure" flag set (i.e. isn't sent over HTTP). Sure if the user logged-in again on the HTTP page you could exploit this with a transparent proxy but there's very little outside of implementing HPKP that BitBucket could do to prevent that attack.

Exactly

But even shutting down access to port 80 on the server wouldn't be enough: the attacker only needs the victim to send the request, it doesn't need for the plaintext request to actually reach the server

(did you mean HSTS instead of HPKP, btw? The scenario I described didn't involve MITM of a HTTPS connection, and thus HPKP wouldn't be strictly needed )

also, I agree that the condition under which this check might be useful are quite convoluted... since Security is often in tension with Usability there is a case to be made for less defense-in-depth, and removing (potentially?) redundant checks... but I think we should be wary of making simplistic arguments for it, due to how delicate web app security is

Agreed; killing port 80 just decreases the chances the browser makes subsequent port 80 requests.

I still think the referrer is only helping paper over a deeper design flaw (using cookies to carry post state) at the expense of getting some users to trade privacy for availability, and decreasing performance/opening up attacks for people that install extensions as a workaround.

Generally your MITM scenario won't work. You won't have access to secure cookies to pass along in the attack.

I do agree though if you can spoof arbitrary cookies, I don't see how you are secure from MITM attacks.

The proxy would have to spoof the secure cookie flags (and also maybe rewrite JavaScript to request http instead of https) but MITM attacks are already costly, and bitbucket is a big, high value target; this is all within the reach of industrial espionage or state sponsored attack (or bored teens).

I just read up on hsts and hpkp. They both seem pretty broken in the face of http MITM attacks (why aren't they part of the secure dns stuff?!?). Also, hpkp is often disabled for self signed and imported (private) CA certs. sigh.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key...

They both look much better than the django referrer hack though. Thanks for the pointer.

Ugh. HSTS / HPKP make my head hurt. Best practice on the client side is rapidly converging to 'make the web browser stateless', with things like tails, or just leaving private browsing mode on 100% of the time.

Both those protocols are significantly weakened by stateless clients!

Wasn't implying this, I meant it as "token sufficient, referrer of low value".
This is Django's CSRF module, and it only requires the referer when operating behind HTTPS.

The requirement is there to close off edge cases where an attacker MITMs the initial non-HTTPS request in order to set up compromise of CSRF for future HTTPS requests. HSTS by itself can't solve that. If and when browser support for the Origin header gets more widespread, it'll be possible to secure this without checking Referer. But for now, that's not an option.

I really don't think this is a big deal. I run a medium size website with well over 2000 uniques users per day and also require the referer header to use the website. So far, I've yet to receive a single complaint or find a browser that doesn't send it.

It might be optional as per the spec, but it's completely ubiquitous at this point, and provides an easy way to add an extra layer of safety for web developers.

(comment deleted)
Twitter does this. If you filter all referrers, all Ajax requests fail (even posting something).
How dare Bitbucket have a bug in their code while the rest of us live and breath standards compliant perfection?