<rant>
So I’ve got my knickers in a twist again. Recently I was playing around with sending some OData to my SAP server when it refused me. Now, I didn’t like that, but at least it was kind enough to tell me why. Apparently I hadn’t fed it a CSRF token. OK, so I looked in the headers of the GET that did work, and lo and behold there was a CSRF token there. I fed that into the POST I was doing, and bingo it worked.
Now it seems to me that many many people have hit the same thing and found the same solution. Indeed, I asked around some people I knew and they told me: “Get over it Chris, it’s in the header of your GET, it lasts all session, just use it!” But me being me, no, I wouldn’t accept that!
Slight aside – they also mentioned “Damnit, I remember when that patch came in, it buggered up my custom Gateway app and I had no warning that it was coming, took me ages to figure out why it wasn’t working.”
So I thought – OK? Why? Why do we have CSRF protection in the first place, what on earth is it?
CSRF protection – Cross Site Request Forgery protection, according to the websites I read is supposed to protect against the case where unknown to a user a cookie in the browser used for authentication allows a malicious site to alter data on your system. (And in the case of gateway, your SAP system).
So to send a PUT or POST or DELETE (the verbs that can change data) from a browser without user knowing is going to involve 1 of 2 things.
a) An injection of HTML on the page adds either a form that is going to POST some data (typical type of attack CSRF protects against) or a link e.g. img tag which GETs data.
b) An injection of some script, e.g. JS on page that is going to do the PUT/POST/DELETE
In the case of (a – POST) the payload will be malformed and Gateway isn’t going to accept that as valid OData – so no security worries anyway. And for (a – GET) CSRF protection isn’t even applied.
In the case of (b) well if I can embed JS, I can just as easily embed a GET pull the header and then do an update with the CSRF token. Indeed the sites that advocate for the CSRF token approach make it clear that it cannot protect you in the case you have malicious Javascript.
In the case that the script is running on a page from a different domain, then CORS will kick in and stop the access – but if somehow the injection is on my own domain, I don’t see how we’re protected.
So I was at a loss. What protection does CSRF actually offer Gateway?
I further researched:
There’s a great explanation, which does better than I have at:
It is recommended that you familiarise yourself with CSRF, what the attack vectors are, and what the attack vectors are not. We recommend starting withthis information from OWASP.
Simply put, an attacker can coerce a victims browser to make the following types of requests:
- All
GET
requestsPOST
requests with bodies of typeapplication/x-www-form-urlencoded
,multipart/form-data
andtext/plain
An attacker can not:
- Coerce the browser to use other request methods such as
PUT
andDELETE
- Coerce the browser to post other content types, such as
application/json
- Coerce the browser to send new cookies, other than those that the server has already set
- Coerce the browser to set arbitrary headers, other than the normal headers the browser adds to requests
Since
GET
requests are not meant to be mutative, there is no danger to an application that follows this best practice. So the only requests that need CSRF protection arePOST
requests with the above mentioned content types.
Since Gateway does not support POST requests with bodies of type application/x-www-form-urlencoded,multipart/form-data and text/plain (or if it does there’s your problem right there!) there is no need for CSRF protection.
I then had a fun conversation on Twitter with Ethan
@wombling @grahamrobbo @chris_rae01 Hmmm. I think you’re being a bit hard on them. There are some advantages to being conservative here.
— Ethan Jewett (@esjewett) August 20, 2015
@wombling @grahamrobbo @chris_rae01 What if a browser starts allowing PUT requests or different form body encodings?
— Ethan Jewett (@esjewett) August 20, 2015
@wombling @grahamrobbo @chris_rae01 Layered, conservative security decisions helps in guarding against escalation attacks like CSRF.
— Ethan Jewett (@esjewett) August 20, 2015
@wombling @grahamrobbo @chris_rae01 It’s one request at the beginning of your session.
— Ethan Jewett (@esjewett) August 20, 2015
@wombling @grahamrobbo @chris_rae01 You have a lot of faith.
— Ethan Jewett (@esjewett) August 20, 2015
@wombling @grahamrobbo @chris_rae01 You assume no zero-days being exploited rather than reported. That’s an invalid assumption.
— Ethan Jewett (@esjewett) August 20, 2015
The great thing about chatting with Ethan is you always come out having learnt something.
He makes a good point, and I’ll paraphrase him:
“The best security is deep and many layered and protects not only against the things that you know may happen, but also against those that you’re pretty sure won’t.”
I was wrong – “to send a PUT or POST or DELETE (the verbs that can change data) from a browser without user knowing is going to involve 1 of 2 3 things. With the third being:
An exploitation of a hitherto unknown browser bug that allows it.
So now I’m confused. Is it worthwhile implementing the hassle that is CSRF protection, including the potential slowdown in speed of response from the solution (a paramount concern in a mobile app) for a situation that might happen.
When I’m writing ABAP code, I’m happy to trade away performance of the code for ease of maintenance. I don’t use pointers (field symbols) to loop over data that I do not intend to change, because some fool could come along later and accidentally do just that. If I instead use a work area, there isn’t that risk.
So in some respects I already do work that makes the solution slower to ensure lower risk, so shouldn’t I just do the CSRF thingy?
However, it is the reason for the risk – I don’t trust that the people maintaining the code after I leave will understand what I have done in my implementation of CSRF protection and won’t make a mistake. Even if I’m using UI5 in my application to update my SAP system, will they remember to call the refreshSecurityToken method every time before a PUT, POST or DELETE? Will they test it? Will they let the session expire in the testing so that they actually need to call the refreshSecurityToken method? I really hope so, but I doubt it. I see applications going into error and data not being updated when it should have been, because of “needless” CSRF protection.
So what I see is this: Security in enterprise is paramount, Gateway is enterprise software, it needs to be secure. So SAP made it so, even if it hasn’t really made a big difference or fixed any known security holes. But, “just in case”. However, custom code (and even standard code 😉 ) will have bugs, ones that rely on sessions timing out are particularly hard to test and will get through. The risk to your Gateway based mobile app is greater by having CSRF protection enabled than it is to your data being maliciously hacked through zero-day exploits. But I guess it depends on what that data is 🙂 .
</rant>
OK, one final bit…
<rant>
Given that I might not actually be using my Gateway for a UI app but for machine to machine transactions, would it PLEASE be possible that if I provide a valid authentication header in the PUT/POST/DELETE that we ignore the CSRF thingy? If I can somehow come up with a valid auth header, then we aren’t protecting anything with a CSRF token, we’re just making transactions slower by requiring multiple round trips that shouldn’t be needed.
</rant>
I feel better now. 🙂
Read how this discussion unfolds over at SCN…
http://scn.sap.com/community/gateway/blog/2014/08/26/gateway-protection-against-cross-site-request-forgery-attacks#comment-611490
P.S. my last post from SCN comment thread as I think it’s an important summary:
The thing is, by not implementing CSRF protection, we aren’t making our services insecure. There are no known ways to use CSRF against Gateway currently.
There is the case of protection against unknown attacks, but is that worth the cost, risk, effort?
Not using CSRF protection does not mean you are making your service insecure. It just trading “just in case” against real life complexity, risk and cost.
Depending on the data concerned, that “just in case” might be worth it. It won’t always be.
Architects have a responsibility to their companies to balance these risks and decide. We have the responsibility to inform them clearly and not just pretend that security is the only and overwhelming factor to consider.
Sometimes we put security on a pedestal and everything has to be done to address it. But we should remember that everything should have a risk/reward curve and sometimes NOT coding for a security risk is actually less risk than coding for it.