Hi everyone I make simple SPA application with JS and Kinvey. I have advertisements and every advert. must have views - how many times is seen(when "GET" request for that advert is called, another "PUT" request is called for the advert with increased views). The problem is that I can't figure out which headers to use: Authorization basic with username:pass and "Kinvey + authToken" return 401 Unauthorized. How to modify collection element which is not created by the currently logged in user?
You will want to use the Javascript SDK which means you don't have to do the quite complicated login / token generation process yourself. It's not a Basic Auth system. The SDK's will handle everything for you.
You cannot by default modify elements that are not created by the logged-in user, which is of course a good idea for security reasons. But, in the Collection Settings, you can change the collection permissions from "Shared" to "Public" to allow anybody write access to any element.
If you want finer grained controls, you can use Business Logic to inspect ACLs at runtime: http://devcenter.kinvey.com/tutorials/using-acls
Related
I want to implement authorization layer on my microservices project. I have 3 microservices customer-service, workspace-service and cloud-service. So if a customer want to create a cloud instance he will create on behalf of a workspace which means that the cloud instance will belong to the workspace instead of him and also he may invite other customer to the workspace, and have access to the cloud instance. The data structure may looks like this.
// workspace
{
"workspaceId": "ws-123",
"customers": ["customer-123", "customer-456"]
}
// cloud-instance
{
"cloudId": "cloud-123",
"workspaceId: "ws-123"
}
I want to implement authorization logic that check if a user has access to a particular cloud instance. In order to do that I need to have workspaceId somewhere else in my authentication object. One thing that I can think of is that to put workspaceId in the jwt claims so my jwt may looks like this.
header.{ ..., workspaceId: ["ws-123"] }.signature
but the drawback of this solution is that the workspaceId claim won't be updated until the token has been refresh.
another solution that is to implement a service that query data from workspace-service and use it to validate.
const hasAccess = (customerId, workspaceId_on_cloud_instance) => {
let actual_workspaceId_that_he_has = workspace_service_exposed_api.findWorkspaceByCustomerId(customerId)
return actual_workspaceId_that_he_has == workspaceId_on_cloud_instance
}
but this approach would heavily rely on workspace-service if workspace-service is down then the other service can not handle a request at all since it doesn't have access to workspaceId.
So IMHO I would rather go for the 1st option since I use oauth2.0 and token will be refresh every 30s, but is it bad practice to do that? I wonder if there's better solution.
Having 3 microservices you cannot implement functionality with assumption that one service is down. I have feeling that access token lifespan is also defined based on this restriction - to have up to date data in the token. As I correctly understand, in worst case there is also ~30 sec. delay related to workspaceId update in token payload.
Token claim will change only when you invite or remove person from workspace so this service must work anyway. I would use 2nd solution with longer token lifespan to not generate it so often.
Another solution is to generate new token every time when workspace is changed - you can treat adding/removing to workspace as a business logic that invalidates token, but probably in this case communication to workspace service is also required.
If you are afraid that microservice will be down or you will have problem with communication, maybe you should focus more on app infrastructure or choose a new solution based on monolith application.
And back to question from title - adding any custom claim to token payload is standard approach.
I have endpoints coded in Nodejs... I use the following codes to keep them safe...
const corsOption = {
origin: ['https://www.mywebsite.com'],
};
app.use(cors(corsOption));
if (host !== "myendpoint.com") {
return res.status(403).json({ message: "forbidden access" });
}
will these keep my endpoints safe... or do I have to do anything more for my endpoints to keep them safe... I don't want bots or anyone else to use it... I know that they are public but I want to restrict access... pls, any help or suggestion ???
thank you
To be sure you can control who can access your endpoint, you can setup a token authentication.
When you send a request to your endpoint, the header should include:
Authorization: Token {your token}
And in your endpoint, you can check if the token is authorized or not (by storing authorized token in a database). If the token is not recognized, you can send back a 403 error.
If your website accesses your endpoints, this means that any browser that can display your website must also be able to access your endpoints. Requests are not made by your website, they are made by browsers visiting your website.
You must first ask how much you want to restrict access:
Restrict to individual known users to whom you send a password via mail, which they must then type into your website ("log on") before they can make any requests to your endpoints.
Restrict to users who have self-registered. Can anyone in the world then self-register, or do you demand confirmation via an email address?
Restrict to users who can log on with their Google (or Facebook, or ...) account.
Zain_Ul_Din's answer shows details of a possible implementation for the "self-registration" case. See also What's the best way to add social login (Sign in with Google) to existing email/password app and database?
you can implement user authentication and authorization in your Node js app to restrict access.
for this you can use the jsonwebtoken npm package.
Look up John Smilga's node and express projects on google for a 10hr video including 4 projects. One of the projects introduces JSON web tokens and how to use them.I highly recommend that.
You can also use the express-rate-limit package. With this you should be able to 'limit' how many requests a user can make to your API endpoints within a set amount of time. If the requests exceed that limit then this middleware steps in and stops further access (Haven't tested it in production myself but looks good)
I'm building a chat dashboard and widget with which a customer should be able to put the widget into their page. Some similar examples would be Intercom or Drift.
Currently, the "main" application is written in Meteor.js (it's front end is in React). I've written a <Widget /> component and thrown it inside a /widget directory. Inside this directory, I also have an index.jsx file, which simply contains the following:
import React from 'react';
import ......
ReactDOM.render(
<Widget/>,
document.getElementById('widget-target')
);
I then setup a webpack configuration with an entry point at index.jsx and when webpack is run spits out a bundle.js in a public directory.
This can then be included on another page by simply including a script and div:
<script src="http://localhost:3000/bundle.js" type="text/javascript"></script>
<div id="widget-target"></div>
A few questions:
What is wrong with this implementation? Are their any security issues to be aware of? Both the examples linked earlier seem make use of an iframe in one form or another.
What is the best way to communicate with my main meteor application? A REST API? Emit events with Socket.io? The widget is a chat widget, so I need to send messages back and forth.
How can I implement some sort of unique identifier/user auth for the user and the widget? Currently, the widget is precompiled.
1 What is wrong with this implementation? Are their any security issues to be aware of? Both the examples linked earlier seem make use of an iframe in one form or another.
As #JeremyK mentioned, you're safer within an iFrame. That being said, there's a middle route that many third parties (Facebook, GA, ...) are using, including Intercom:
ask users to integrate your bundled code within their webpage. It's then up to you to ensure you're not introducing a security vulnerability on their site. This code will do two things:
take care of setting up an iframe, where the main part of your service is going to happen. You can position it, style it etc. This ensure that all the logic happening in the iframe is safe and you're not exposed.
expose some API between your customer webpage and your iframe, using window messaging.
the main code (the iframe code) is then loaded by this first script asynchronously, and not included in it.
For instance Intercom ask customers to include some script on their page: https://developers.intercom.com/docs/single-page-app#section-step-1-include-intercom-js-library that's pretty small (https://js.intercomcdn.com/shim.d97a38b5.js). This loads extra code that sets the iFrame and expose their API that will make it easy to interact with the iFrame, like closing it, setting user properties etc.
2 What is the best way to communicate with my main meteor application? A REST API? Emit events with Socket.io? The widget is a chat widget, so I need to send messages back and forth.
You've three options:
Build your widget as an entire Meteor app. This will increase the size of the code that needs to be loaded. In exchange for the extra code, you can communicate with your backend through the Meteor API, like Meteor.call, get the reactivity of all data (for instance if you send a response to a user through your main Meteor application, the response would pop up on the client with no work to do as long as they are on the same database (no need to be on the same server)), and the optimistic UI. In short you've all what Meteor offers here, and it's probably going to be easier to integrate with your existing backend that I assume is Meteor.
Don't include Meteor. Since you're building a chat app, you'll probably need socket.io over a traditional REST API. For sure you can do a mix of both
Use Meteor DDP. (it's kind of like socket.io, but for Meteor. Meteor app use that for all requests to the server) This will include less things that the full Meteor and probably be easier to integrate to your Meteor backend than a REST API / socket.io, and will be some extra work over the full Meteor.
3 How can I implement some sort of unique identifier/user auth for the user and the widget?
This part should probably do some work on the customer website (vs in your iframe) so that you can set cookies on his page, and send that data to your iframe that's gonna talk to your server and identify the user. Wether you use artwells:accounts-guest (that's based on meteor:accounts-base) is going to depend on wether you decide to include Meteor in your iframe.
If you don't have Meteor in your iframe, you can do something like:
handle user creation yourself, by simply doing on your server
.
const token = createToken();
Users.insert({ tokens: [token] });
// send the token back to your iframe
// and set is as a cookie on your customer website
then for each call to your server, on your iframe:
.
let token;
const makeRequest = async (request) => {
token = token || getCookieFromCustomerWebsite();
// pass the token to your HTTP / socket.io / ... request.
// in the header of whatever
return await callServer(token, request);
};
in the server have a middleware that sets the user. Mine looks like:
.
const loginAs = (userId, cb) => {
DDP._CurrentInvocation.withValue(new DDPCommon.MethodInvocation({
isSimulation: false,
userId,
}), cb);
};
// my middleware that run on all API requests for a non Meteor client
export const identifyUserIfPossible = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return next();
}
const user = Users.findOne({ tokens: token });
if (!user) {
return next();
}
loginAs(user._id, () => {
next();
// Now Meteor.userId() === user._id from all calls made on that request
// So you can do Meteor.call('someMethod') as you'd do on a full Meteor stack
});
};
Asking your customers to embed your code like this doesn't follow the principles of Security by Design.
From their point of view, you are asking them to embed your prebundled code into their website, exposing their site up to any hidden security risks (inadvertent or deliberately malicious) that exist in your code which would have unrestricted access to their website's DOM, localstorage, etc.
This is why using an iframe is the prefered method to embed third party content in a website, as that content is sandboxed from the rest of it's host site.
Further, following the security principle of 'Least Privilege' they (with your guidance/examples) can set the sandbox attribute on the iframe, and explicitly lockdown via a whitelist the privileges the widget will have.
Loading your widget in an iframe will also give you more flexibility in how it communicates with your servers. This could now be a normal meteor client, using meteor's ddp to communicate with your servers. Your other suggestions are also possible.
User auth/identification depends on the details of your system. This could range from using Meteor Accounts which would give you either password or social auth solutions. Or you could try an anonymous accounts solution such as artwells:accounts-guest.
html5rocks article on sandboxed-iframes
My app consists of several PHP endpoints which are accessible via AJAX. The problem is they are also accessible via anyone who makes an HTTP request to the same endpoint. I can add checks for HTTP_X_REQUESTED_WITH and HTTP_REFERER as specified in this answer, but these can be spoofed. I could add a secret key that needs to be posted with the request, but anyone viewing the javascript and/or the console would be able to see this key. What is the solution here?
People often think that because they're using Ajax requests regular sessions don't work. They do.
If you have an endpoint to delete something from the database that's visible in the source code, such as:
example.com/user/1/delete
You can protect this request from non authenticated users the same way you would when using a non Ajax HTTP request in the browser. Using sessions. If the user has the privileges to remove users, this route will work, otherwise return an error (or do nothing).
You can also protect an API using OAuth. There's a great document here that explains how it works: http://tatiyants.com/using-oauth-to-protect-internal-rest-api/
Most of the answers are not helpful if you have your app and your api on separate domains for example app.example.com and api.example.com - in that case sessions won't work and you would have to turn to OAuth which is quite a big hammer for such a simple problem.
Here is what I would do:
I assume you have users in a database and a unique identifier like user_id=12345. I also assume that you have your Jobs in a Database and they also have unique ID's like job_id=6789.
First on app.example.com you encrypt both IDs with something fast and easy like Blowfish:
$secret_uid = mcrypt_encrypt(MCRYPT_BLOWFISH, "your_secret", strval($user_id));
$secret_jid = mcrypt_encrypt(MCRYPT_BLOWFISH, "your_secret", strval($job_id));
I assume your endpoint would work somewhat like this:
api.example.com/jobs/delete/<job_id>/<user_id>
so now from Ajax you call that endpoint, but instead of calling with plain IDs
api.example.com/jobs/delete/6789/12345
you call it with the encrypted IDs:
api.example.com/jobs/delete/6A73D5B557C622B3/57F064C07F83644F
On the API side of your software you decrypt the parameters:
$jid = mcrypt_decrypt(MCRYPT_BLOWFISH, "your_secret", <param_1>);
$uid = mcrypt_decrypt(MCRYPT_BLOWFISH, "your_secret", <param_2>);
Now you can search your db for uid and jid and perform whichever task you were planning to do. Make sure that a user can only delete his own jobs of course.
I admit this is not a 100% solution, but it leaves an attacker with a lot of guess work - he would have to guess the user_id and a matching job_id, the encryption algo and your secret. It does not protect against running millions of brute force attempts to guess a matching pair, but it put's the odds in your favor (and you should have some sort of quota limitation protection of your endpoints anyway).
Good luck!
There isn't one. If you give someone some data, then they can process it in whatever way they like. You can't control what happens to it after it leaves your server.
Likewise, you can't control what data they send to the endpoint.
it is very important for a developer to put authentication for API or web services. dchacke and BugHunterUK has given perfect answers, I just want show you simple code I use to make very simple and easy to use authentication.
Adding Session for the authentication
you can add session, and session timeout for your APIs so, only your app can use this, you can start session when front page of your app is loaded, you can set timeouts and also restrict the different service for different users by sessions.
General Idea how to do that
<?php
if(!empty($_SESSION['api_session']) && $_SESSION['api_session'] == 'usertype'){
//usertype comprise of what access you want to give
//guest, registered user, stack holder, admin etc.
...
header('Content-Type:application/json;');
echo json_encode($output);
}
I'm at a total loss here. I believe I'm right in thinking there is no longer any JS API for twitter which just sucks hugely.
However I realise looking at this I could just use ajax and react to the responses from this:
https://dev.twitter.com/rest/reference/post/statuses/update
OAuth Signature Generator
Example Request POST
https://api.twitter.com/1.1/statuses/update.json?status=Maybe%20he%27ll%20finally%20find%20his%20keys.%20%23peterfalk
However when I post to that url I get the following:
{"errors":[{"code":215,"message":"Bad Authentication data."}]}
Bad Authentication data -> this is very self explanatory: Your Authentication is Bad; in other word, you are not authorized to use that API method.
Since you use POST method, make sure you set your APP access level to Read & Write.
Sign in to apps.twitter.com, and in the Applications Management page for your app, click the Permissions tab. There you can change your access level.
For further reading, please see this answer.