Secure a REST interface without login - rest

I recently succeeded in building a page that loads data via an ajax get call to a REST interface (that runs on my server) and then uses the data to construct a map overlay for Google maps via JS.
I managed to do this but now I have concerns about the security of my data. Obviously everybody could just use curl to load the overlay data from my REST interface. However, I do not want to make my data so easily available, since they are kind of the business value of my page...
Is saw many solutions on the web that all require a login of the user.
However, this should not be required on my page.
Is there an easy solution to this problem, without the user having to use a log in or something? Basically I only want to allow my web application to query data from my REST interface, but not anyone else.
One solution that came to my head is to pass the data directly from php into JS, when the page is loaded. However this looks like a real ugly solution to me...

On a RESTful interface, I suppose you want to avoid login into a session. You have basically 2 more ways :
use IP address filtering if the web application run on a private network with known IP addresses
pass an identification token in the request headers or as a request parameter. The token has to be passed along in all the requests.

Related

RESTful API: how to distinguish users requests from front-end requests?

So, I have a RESTful API (built with Hapi.js) that has endpoints consumed by users and my front-end app (built with Next.js). GET api/candies is one of them, I'll take it as an example.
The front-end asks the list of candies stored in my DB and displays them on a page anyone can access (it has to be this way). The front-end doesn't provide an API token since people could read/use it. But, users who want to get this list of candies (to build whatever they want with it) must provide a valid API token (which they get by creating an account on my front-end app).
How could my API tell if a request for api/candies is from a user or from my front-end app, so it can verify (or not) the validity of their token?
I'm wondering if my problem isn't also about web scraping.
Can anyone help me please? :D
I thought about the same problem a while ago. If your frontend has a client side REST client (JS+XHR/fetch), then I don't think it is possible to do this reliably, because no matter how you identify your frontend REST client, your users will be able to copy it just by checking the HTTP requests in browser via CTRL+SHIFT+I. There are even automation tools, which use the browser e.g. Selenium. If you have a server side REST client (e.g. PHP+CURL), then just create a consumer id for the frontend and use a token. Even in this case I can easily write a few lines of code that uses the frontend for the same request. So if you want to sell the same service for money that you provide for free on your frontend, then you are out of luck here. This does not mean that there won't be consumers who are willing to pay for it.
I think your problem is bad business model.
Your requirement can be addressed by inspecting different headers sent by different user agents. You can also add custom headers from your front-end and validate the same on the backend.

WOPI Host implementation issues

We’re trying to implement a Wopi Host following the protocol to integrate with OWA, as documented in here, and we’re having some issues with some points:
We have implemented a simple host that is only capable of viewing files, that is, it implements the CheckFileInfo and GetFile views. In a test environment, the flow is working and we’re able to view the files in OWA. The point is, when executing the Wopi Validator (the web and the docker version), we’re having an error in the GetFile operation because the validator is trying to access the endpoint with two // at the end:
host/wopi/files/file_id//contents
Is this a known issue that is happening only in the validator? Why are the two ‘/’ being appended to the end of the WopiSrc? How can we address this issue?
We have read some posts here stating that the editing is required in order to officially validate our OWA integration with Microsoft. Is this true? Isn’t the CheckFileInfo and GetFile views the only ones necessary to implement a simple Wopi host capable only of viewing files? We’re just passing the required information in the response of the CheckFileInfo operation. We’re not using FileUrl or any other parameter but the required ones. As far as I can see, these two views are the only one required for viewing files with OWA, such as stated here
Additionally, we’re having an issue in the first part of the flow, when the browser sends a request to OWA and passes the token and the WopiSrc. We were only able to make the flow work passing the token in the query string via the GET method. If we put it under a JSON with a POST method, the OWA simply ignores it and does not make an attempt to call the Wopi Host at all, via the WopiSrc. Could someone enlighten us a bit on this matter to figure out what may be happening?
Furthermore, we’re stuck in some point of token validation. The docs are crystal clear when they say that the token is generated by the host, and that it should be unique for a single user/file combination. We have done that. The problem is, how are we supposed to know what is the user that is trying to access a resource, when the request comes from OWA? For example, when the OWA calls the host in the CheckFileInfo and GetFile views, it passes us the token. But how could we know the user information as well? Since the token is for a single file (which we have in the address of the endpoint being accessed) and for a single user, how can we validate the user at this point? We have not found any header or placeholder value that could be used to extract this information when receiving a request from OWA, and we’re a bit lost here. We’ve thought about appending the user information to the token, and then extracting it back, but for what I could see, doing that I’m only ensuring that the token has not been modified between requests. Does anyone have any idea?
Regarding the validation with Microsfot demands the edit functionality.
For the POST situation, the submission must be made as a "form" not as JSON.
The token validation is completely open, you must choose the way you think would be the best approach. JWT is a good alternative in this case.

How to call Salesforce REST API from external web forms

I am a bit confused. The requirement is that we need to create a REST API in Salesforce(Apex class) that has one POST method. Right now, I have been testing it with POSTMAN tool in 2 steps:
Making a POST request first with username, password, client_id, client_secret(that are coming from connected app in Salesforce), grant_type to receive access token.
Then I make another POST request in POSTMAN to create a lead in Salesforce, using the access token I received before and the body.
However, the REST API that I have in Salesforce would be called from various different web forms. So once someone fills out the webform, on the backend it would call this REST API in Salesforce and submits lead request.
I am wondering how would that happen since we can't use POSTMAN for that.
Thanks
These "various different web forms" would have to send requests to Salesforce just like Postman does. You'd need two POST calls (one for login, one to call the service you've created). It'll be bit out of your control, you provided the SF code and proven it works, now it's for these website developers to pick it up.
What's exactly your question? There are tons of libraries to connect to SF from Java, Python, .NET, PHP... Or they could hand-craft these HTTP messages, just Google for "PHP HTTP POST" or something...
https://developer.salesforce.com/index.php?title=Getting_Started_with_the_Force.com_Toolkit_for_PHP&oldid=51397
https://github.com/developerforce/Force.com-Toolkit-for-NET
https://pypi.org/project/simple-salesforce/ / https://pypi.org/project/salesforce-python/
Depending how much time they'll have they can:
cache the session id (so they don't call login every time), try to reuse it, call login again only if session id is blank / got "session expired or invalid" error back
try to batch it somehow (do they need to save these Leads to SF asap or in say hourly intervals is OK? How did YOU write the service, accepts 1 lead or list of records?
be smart about storing the credentials to SF (some secure way, not hardcoded). Ideally in a way that it's easy to use the integration against sandbox or production changing just 1 config file or environment variables or something like that

Prevent direct api access from browser

Currently as it stands, if a user reads the source of my web application, they'd be able to determine the direct URIs of all the RESTful services my web application utilizes.
The problem I see is this: My web application knows how to correctly use the API, and I might not have thought of every single validation known to man to prevent bad data from being sent through the API.
And so with that is there a method to prevent "direct" access to the API and limit it only to my web application?
P.S. As an FYI: API calls concerning a user are protected by the presence of a user-specific cookie which is only issued upon login. This means I'm not too afraid of User X being able to directly modify User Y's data through the API.
No.
If the browser is making the request, the user can spoof the request. Period.
My web application knows how to correctly use the API
That's good, but that's leading you down the path of assuming client-side functionality executed as intended. Never make that assumption.
I might not have thought of every single validation known to man to prevent bad data from being sent through the API
This statement leads me to believe that the API itself is more complex than it needs to be. The best thing you can do is simplify. It's difficult to be more specific without seeing specific code, but API requests should be fairly simple and straightforward and the same techniques to prevent malicious code from getting through should be applied universally. The same general rules apply here as in any web application interaction...
Never trust anything that came from the client
Never assume client-side code executed as intended
Never execute input as code, always treat it as a raw value
and so on...
As you mention toward the end, you've already taken care of authentication and authorization for the requests. Given that, if User X is permitted to make a given API call, then what you're essentially asking is, "How do I allow User X to make an API call without allowing User X to make an API call?" The server can't tell the difference. A request is a request.
Sure, there are things you can try, such as always including some custom header in requests made from code. But anybody can inspect that request and spoof that header. The user's browser isn't part of your application and isn't under your control.

ASP.NET Web API Authentication Options

What options are available for authentication of an MVC3 Web API application that is to be consumed by a JQuery app from another domain?
Here are the constraints/things I've tried so far:-
I don't want to use OAuth; for private apps with limited user bases I cannot expect end users to have their accounts on an existing provider and there is no scope to implement my own
I've had a fully functioning HMAC-SHA256 implemention working just fine using data passed in headers; but this doesn't work in IE because CORS in IE8/9 is broken and doesn't allow you to send headers
I require cross-domain as the consuming app is on a different domain to the API, but can't use jsonp becuase it doesn't allow you to use headers
I'd like to avoid a token (only) based approach, as this is open to replay and violates REST by being stateful
At this point I'm resigned to a HMAC-SHA256 approach that uses either the URL or querystring/post to supply the hash and other variables.
Putting these variables in the URL just seems dirty, and putting them in the querystring/post is a pain.
I was succesfully using the JQuery $.ajaxSetup beforeSend option to generate the hash and attach it to the headers, but as I mentioned you can't use headers with IE8/9.
Now I've had to resort to $.ajaxPrefilter because I can't change the ajax data in beforeSend, and can't just extend data in $.ajaxSetup because I need to dynamically calculate values for the hash based on the type of ajax query.
$.ajaxPrefilter is also an issue because there is no clean/simple way to add the required variables in such a way that is method agnostic... i.e. it has to be querystring for GET and formdata for POST
I must be missing something because I just cannot find a solution that:-
a) supports cross-domain
a) not a massive hack on both the MVC and JQuery sides
c) actually secure
d) works with IE8/9
There has to be someone out there doing this properly...
EDIT
To clarify, the authentication mechanism on the API side is fine... no matter which way I validate the request I generate a GenericPrincipal and use that in the API (the merits of this are for another post, but it does allow me to use the standard authorization mechanisms in MVC, which I prefer to rolling my own... less for other developers on my API to learn and maintain)
The problem lies primarly in the transfer of authentication information from the client to the API:-
- It can't rely on server/API state. So I can't pass username/password in one call, get a token back and then keep using that token (open to replay attack)
- Anything that requires use of request headers is out, because IE uses XDR instead of XHR like the rest of the browsers, and it doesn't support custom headers (I know IE10 supports XHR, but realistically I need IE8+ support)
- I think I'm stuck generating a HMAC and passing it in the URL somewhere (path or querystring) but this seems like a hack because I'm using parts of the request not designed for this
- If I use the path there is a lot of messy parsing because at a minimum I have to pass a username, timestamp and hash with each request; these need to be delimited somehow and I have little control over delimiters being used in the rest of the url
- If I use data (querystring/formdata) I need to change the place I'm sending my authentication details depending on the method I'm using (formdata for POST/PUT/etc and querystring for GET), and I'm also polution the application layer data space with these vars
As bad as it is, the querystring/formdata seems the best option; however now I have to work out how to capture these on each request. I can use a MessageHandler or Filter, but neither provide a convienient way to access the formdata.
I know I could just write all the parsing and handling stuff myself (and it looks like I will) but the point is I can't believe that there isn't a solution to this already. It's like I have (1) support for IE, (2) secure and (3) clean code, and I can only pick two.
Your requirements seem a little bit unjustified to me. You can't ever have everything at the same time, you have to be willing to give something up. A couple of remarks:
OAuth seems to be what you want here, at least with some modifications. You can use Azure's Access Control Service so that you don't have to implement your own token provider. That way, you have "outsourced" the implementation of a secure token provider. Last I checked Azure ACS was still free. There is a lot of clutter when you look for ACS documentation because people mostly use it to plug into another provider like Facebook or Google, but you can tweak it to just be a token provider for your own services.
You seem to worry a lot about replay attacks. Replay attacks almost always are a possibility. I have to just listen to the data passing the wire and send it to your server, even over SSL. Replay attacks are something you need to deal with regardless. Typically what I do is to track a cache of coming requests and add the hash signature to my cache. If I see another request with the same hash within 5 minutes, I ignore it. For this to work, I add the timestamp (millisecond granularity) of the request and some derivative of the URL as my hash parameters. This allows one operation per millisecond to the same address from the same client without the request being marked as replay attack.
You mentioned jQuery which puzzles me a bit if you are using the hashing method. That would mean you actually have your hash algorithm and your signature logic on the client. That's a serious flaw because by just inspecting javascript, I can now know exactly how to sign a request and send it to your server.
Simply said; there is not much special in ASP.NET WebAPI when it comes to authentication.
What I can say is that if you are hosting it inside ASP.NET you'll get support by ASP.NET for the authentication and authorization. In case you have chosen for self-hosting, you will have the option to enable WCF Binding Security options.
When you host your WebAPI in ASP.NET, you will have several authentication options:
Basic Authentication
Forms Authentication - e.g. from any ASP.Net project you can enable Authentication_JSON_AppService.axd in order to the forms authentication
Windows Authentication - HttpClient/WebHttpRequest/WebClient
Or explicitly allow anonymous access to a method of your WebAPI